Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Modern Clojure HTTP server and client built for ease of use and performance

License

NotificationsYou must be signed in to change notification settings

AppsFlyer/donkey

Repository files navigation

Donkey CICoverage Status
Clojars Project

Modern Clojure, Ring compliant, HTTP server and client, designed for ease of useand performance

Note: this project is no longer maintained.

Table of Contents

TOC Created bygh-md-toc

Usage

Including the library inproject.clj

[com.appsflyer/donkey"0.5.2"]

Including the library indeps.edn

com.appsflyer/donkey {:mvn/version"0.5.2"}

Including the library inpom.xml

<dependency>    <groupId>com.appsflyer</groupId>    <artifactId>donkey</artifactId>    <version>0.5.2</version></dependency>

Requirements

Building

The preferred way to build the project for local development is using Maven.It's also possible to generate an uberjar using Leiningen, but youmust use Maven to install the library locally.

Creating a jar with Maven

mvn package

Creating an uberjar with Leiningen

lein uberjar

Installing to a local repository

mvn clean install

Start up options

JVM system properties that can be supplied when running the application

  • -Dvertx.threadChecks=false: Disable blocked thread checks. Used by Vert.x towarn the user if an event loop or worker thread is being occupied above acertain threshold which will indicate the code should be examined.
  • -Dvertx.disableContextTimings=true: Disable timing context execution. Theseare used by the blocked thread checker. It doesnot disable executionmetrics that are exposed via JMX.

Creating a Donkey

In Donkey, you create HTTP servers and clients using a -Donkey. CreatingaDonkey is simple:

(nscom.appsflyer.sample-app  (:require [com.appsflyer.donkey.core:refer [create-donkey]]))  (def ^Donkeydonkey-core (create-donkey))

We can also configure our donkey instance:

(nscom.appsflyer.sample-app  (:require [com.appsflyer.donkey.core:refer [create-donkey]]))  (defdonkey-core (create-donkey {:event-loops4}))

There should only be a singleDonkey instance per application. That's becausethe client and server will share the same resources making them very efficient.Donkey is a factory for creating server(s) and client(s) (youcan createmultiple servers and clients with aDonkey, but in almost all cases you willonly want a single server and / or client per application).

Server

The following examples assume these required namespaces

(:require [com.appsflyer.donkey.core:refer [create-donkey create-server]]          [com.appsflyer.donkey.server:refer [start]]          [com.appsflyer.donkey.result:refer [on-success]])

Creating a Server

Creating a server is done using aDonkey instance. Let's start by creating aserver listening for requests on port 8080.

(->           (create-donkey)  (create-server {:port8080})  start  (on-success (fn [_] (println"Server started listening on port 8080"))))

Note that the following example will not work yet - for it to work we need toadd a route which we will do next.

After creating the server westart it, which is an asynchronous call that mayreturn before the server actually started listening for incoming connections.It's possible to block the current thread execution until the server is runningby callingstart-sync or by "derefing" the arrow macro.

The next thing we need to do is define a route. We talk aboutroutesin depth later on, but a route is basically a definition of an endpoint. Let'sdefine a route and create a basic "Hello world" endpoint.

(->  (create-donkey)  (create-server {:port8080:routes [{:handler (fn [_request respond _raise]                                       (respond {:body"Hello, world!"}))}]})  start  (on-success (fn [_] (println"Server started listening on port 8080"))))

As you can see we added a:routes key to the options map used to initializethe server. A route is a map that describes what kind of requests are handled ata specific resource address (or:path), and how to handle them. The onlyrequired key is:handler, which will be called when a request matches a route.In the example above we're saying that we would like any request to be handledby our handler function.

Our handler is a Ring compliant asynchronous handler. If you are not familiarwith theRingasync handler specification, here's an excerpt:

An asynchronous handler takes 3 arguments: a request map, a callback function for sending a response, and a callback function for raising an exception. The response callback takes a response map as its argument. The exception callback takes an exception as its argument.

In the handler we are calling the response callbackrespond with a responsemap where the body of the response is "Hello, world!".

If you run the example and open a browser onhttp://localhost:8080 you willsee a page with "Hello, World!".

Routes

In Donkey HTTP requests are routed to handlers. When you initialize a server youdefine a set of routes that it should handle. When a request arrives the serverchecks if one of the routes can handle the request. If no matching route isfound, then a404 Not Found response is returned to the client.

Let's see a route example:

{:handler      (fn [request respond raise] ...):handler-mode:non-blocking:path"/api/v2":match-type:simple:methods      [:get:put:post:delete]:consumes     ["application/json"]:produces     ["application/json"]:middleware   [(fn [handler] (fn [request respond raise] (handler request respond raise)))]}

:handler A function that accepts 1 or 3 arguments (depending on:handler-mode). The function will be called if a request matches the route.This is where you call your application code. The handler should return aresponse map with the following optional fields:

  • :status: The response status code (defaults to 200)
  • :headers: Map of key -> valueString pairs
  • :body: The response body asbyte[],String, orInputStream

:handler-mode To better understand the use of the:handler-mode, we need tofirst get some background about Donkey. Donkey is an abstraction built on top ofa web tool-kit calledVert.x, which in turn is built on avery popular and performant networking library calledNetty. Netty's architecture is based on the concept of asingle threaded event loop that serves requests. An event loop is conceptually along-running task with a queue of events it needs to dispatch. As long as eventsare dispatched "quickly" and don't occupy too much of the event loop's time, itcan dispatch events at a very high rate. Because it is single threaded, or inother words serial, during the time it takes to dispatch one event no otherevent can be dispatched. Therefore, it's extremely importantnot to block theevent loop.

The:handler-mode is a contract where you declare the type of handling yourroute does -:blocking or:non-blocking (default).:non-blocking means that the handler is performing very fast CPU-bound tasks,or non-blocking IO bound tasks. In both cases the guarantee is that it willnotblock the event loop. In this case the:handler must accept 3 arguments.Sometimes reality has it that we have to deal with legacy code that is doingsome blocking operations that we just cannot change easily. For these occasionswe have:blocking handler mode. In this case, the handler will be called on aseparate worker thread pool without needing to worry about blocking the eventloop. The worker thread pool size can be configured when creating aDonkey instance by setting the:worker-threads option.

:path is the first thing a route is matched on. It is the part after thehostname in a URI that identifies a resource on the host the client is trying toaccess. The way the path is matched depends on the:match-type.

:match-type can be either:simple or:regex.

:simple match type will match in two ways:

  1. Exact match. Going back to the example route at the begining of thesection, the route will only match requests tohttp://localhost:8080/api/v2. It willnot match requests to:
    • http://localhost:8080/api
    • http://localhost:8080/api/v3
    • http://localhost:8080/api/v2/user
  2. Path variables. Take for example the path/api/v2/user/:id/address.:idis a path variable that matches on any sub-path. All the following paths willmatch:
    • /api/v2/user/1035/address
    • /api/v2/user/2/address
    • /api/v2/user/foo/address
      The really nice thing about path variables is that you get the value thatwas in the path when it matched, in the request. The value will beavailable in the:path-params map. If we take the first example, the request will looklike this:
{;; ...:path-params {"id""1035"};; ...}

:regex match type will match on arbitrary regular expressions. For example, ifwanted to only match the/api/v2/user/:id/address path if:id is a number,then we could use:match-type :regex and supply this path:/api/v2/user/[0-9]+/address. In this case the route will only match if aclient requests the path with a numeric id, but we won't have access to the idin the:path-params map. If we wanted the id we could fix it by addingcapturing groups:/api/v2/user/([0-9]+)/address. Now everything within theparenthesis will be available in:path-params.

{:path-params {"param0""1035"}}

We can also add multiple capturing groups, for example the path/api/v(\d+\.\d{1})/user/([0-9]+)/address will match/api/v4.7/user/9/addressand:path-params will include both capturing groups.

{:path-params {"param0""4.7""param1""9"}}

:methods is a vector of HTTP methods the route supports, such as GET, POST,etc'. By default, any method will match the route.

:consumes is a vector of media types that the handler can consume. If a routematches but theContent-Type header of the request doesn't match one of thesupported media types, then the request will be rejected with a415 Unsupported Media Type code.

:produces is a vector of media types that the handler produces. If a routematches but theAccept header of the request doesn't match one of thesupported media types, then the request will be rejected with a406 Not Acceptable code.

:middleware is a vector ofmiddleware functions that will beapplied to the route. It is also possible to supply a "global":middleware vector whencreating a server that will beapplied to all the routes. In that case the global middleware will be appliedfirst, followed by the middleware specific to the route.

Support for Routing Libraries

Sometimes we have an existing service using some HTTP server and routinglibraries such asCompojureorreitit, and we don't have time torewrite the routing logic right away. It's very easy to simply plug all yourexisting routing logic to Donkey without changing a line of code.

We'll use Compojure and reitit as examples, but the same goes for any other Ringcompatible library you use.

reitit

Here is an excerpt from Metosin's reititRing-routerdocumentation, demonstrating how to create a simple router.

(require '[reitit.ring:as ring])(defnhandler [_]  {:status200,:body"ok"})(defnwrap [handler id]  (fn [request]    (update (handler request):wrap (fnil conj '()) id)))(defapp  (ring/ring-handler    (ring/router      ["/api" {:middleware [[wrap:api]]}       ["/ping" {:get handler:name::ping}]       ["/admin" {:middleware [[wrap:admin]]}        ["/users" {:get handler:post handler}]]])))

Now let's see how you would use this router with Donkey.

(->   (create-donkey)  (create-server {:port8080:routes [{:handler app:handler-mode:blocking}]})  start)

That's it!

Basically, we're creating a single route that will match any request to theserver and will delegate the routing logic and request handling to the reititrouter. You'll notice we had to add:handler-mode :blocking to the route.That's because this particular example uses the one argument ring handler. If weadd a three argument arity tohandler andwrap, then we'll be able to remove:handler-mode :blocking and use the default non-blocking mode.

Compojure

Here is an excerpt from James Reeves'Compojure repository on GitHub,demonstrating how to create a simple router.

(nshello-world.core  (:require [compojure.core:refer:all]            [compojure.route:as route]))(defroutesapp  (GET"/" []"<h1>Hello World</h1>")  (route/not-found"<h1>Page not found</h1>"))

To use this router with Donkey we do exactly the same thing we did forreitit's router.

(->   (create-donkey)  (create-server {:port8080:routes [{:handler app:handler-mode:blocking}]})  start)

Static Resources

Every server needs to be able to serve static resources such as HTML,JavaScript, or image files. In Donkey, you configure how to serve static filesby providing a:resources map when creating the server. An example is worth athousand words:

:resources {:enable-cachingtrue:max-age-seconds1800:local-cache-duration-seconds60:local-cache-size1000:resources-root"public":index-page"home.html":routes                       [{:path"/"}                                           {:path"/js/.+\.min\.js"}                                           {:path"/images/.+":produces ["image/*"]}]}

The configuration enables cache handling via theCache-Control header, anddefines when cached resources become stale. The:index-page tells the serverwhich file to serve when a directory is requested, and theresources-root isthe directory where all assets reside.

Now let's take a look at the:routes vector that defines the paths wheredifferent resources are located. The first route defines the file that's servedwhen requesting the root directory of the site. For example, if our site'shostname isexample.com, then when the server gets a requestforhttp://example.com orhttp://example.com/it will serve the index pagehome.html. The file is served from<path to resources directory>/public/home.html

The second and third routes use regular expressions to define which files shouldbe served from thejs andimage directories. here is an example of a requestfor a JavaScript file:

http://example.com/js/app.min.js

In this example, if the unminified files are requested the route won't match:

http://example.com/js/app.js ;; will return 404 not found

The third route defines where images are served from, and it also declares thatit will only serve files with mime typeimage/*. If the request'sAccept header doesn't match an image mime type, then the request will berejected with a406 Not Acceptable code.

Middleware

Overview

The term "middleware" is generally used in the context of HTTP frameworks as apluggable unit of functionality that can examine or manipulate the flow of bytesbetween a client and a server. In other words, it allows users to do things suchas logging, compression, validation, authorization, and transformation (to namea few)of requests and responses.

According totheRingspecification, middleware are implementedashigher-order functionsthat accept one or more arguments, where the first argument is thenexthandler function, and any optional arguments required by the middleware.Ahandler in this context can be either another middleware, oraroute handler. The higher-order function should return a functionthat accepts one or three arguments:

  • One argument: Called when:handler-mode is:blocking with arequest map.
  • Three arguments: Called when:handler-mode is:non-blocking with arequest map,respond function, andraise function. Therespondfunction should be called with the result of the next handler, and theraisefunction should be called when it is impossible to continue processing therequest because of an exception.

Thehandler argument that was given to the higher-order function has the samesignature as the function being returned. It is the middleware author'sresponsibility to call the nexthandler at some point.

Examples

Let's start with a middleware that adds a timestamp to a request. It can becalled with:handler-mode:blocking ornon-blocking:

(defnadd-timestamp-middleware [handler]  (fn    ([request]      (handler        (assoc request:timestamp (System/currentTimeMillis))))    ([request respond raise]     (try       (handler         (assoc request:timestamp (System/currentTimeMillis)) respond raise)       (catch Exception ex         (raise ex))))))

In the last example we updated the request and called the next handler with thetransformed request. However, middleware is not limited to only processing andtransforming the request. Here is an example of a three argument middleware thatadds aContent-Type header to theresponse.

(defnadd-content-type-middleware [handler]  (fn [request respond raise]    (let [respond' (fn [response]                     (try                       (respond                         (update response:headers assoc"Content-Type""text/plain"))                       (catch Exception ex                         (raise ex))))]              (handler request respond' raise))))

As mentioned before, the three argument function is called when the:handler-mode is:non-blocking. Notice that we are doing the processing onthe calling thread - the event loop. That's because the overhead ofcontext switchingand potentially spawning a new thread by offloading a simpleassocorupdate to a separate thread pool would greatly outweigh the processing timeon the event loop. However, if for example we had a middleware that performssome blocking operation on a remote database, then we would need to run it on aseparate thread.

In this example we authenticate a user with a remote service. For the sake ofthe example, all we need to know is that we get back aCompletableFuturethat is executed on a different thread. When the future completes, we check ifwe had an exception, and then either call the nexthandler with the updatedrequest, or stop the execution by callingraise.

(defnuser-authentication-middleware [handler]  (fn [request respond raise]    (.whenComplete      ^CompletableFuture (authenticate-user request)      (reify BiConsumer        (accept [this result exception]          (if (nil? exception)            (handler (assoc request:authenticated result) respond raise)            (raise exception)))))))

Common Middleware

There are some common operations that Donkey provides as pre-made middlewarethat can be found undercom.appsflyer.donkey.middleware.* namespaces. All themiddleware that come with Donkey take an optional options map. The options mapcan be used, for example, to supply an exception handler.

A very common use case is inspecting the query parameters sent by a client inthe url of a GET request. By default, the query parameters are available in therequest as a string under:query-string. It would be much more useful if wealso had a map of name value pairs we can easily use.

(:require [com.appsflyer.donkey.middleware.params:refer [parse-query-params]])(->  (create-donkey)  (create-server {:port8080:routes [{:path"/greet":methods    [:get]:handler    (fn [req res _err]                                          (res {:body (str"Hello,"                                                           (get-in req [:query-params"fname"])""                                                           (get-in req [:query-params"lname"]))})):middleware [(parse-query-params)]}]})  start)

In this example we are using theparse-query-params middleware, that doesexactly that. Now if we make aGET requesthttp://localhost:8080/greet?fname=foo&lname=bar we'll get back:

Hello, foo bar

Another common use case is converting the names of each query parameter into akeyword. We can achieve both objectives with one middleware:

(:require [com.appsflyer.donkey.middleware.params:refer [parse-query-params]])(->  (create-donkey)  (create-server {:port8080:routes [{:path"/greet":methods    [:get]:handler    (fn [req res _err]                                          (res {:body (str"Hello,"                                                           (-> req:query-params:fname)""                                                           (-> req:query-params:lname))})):middleware [(parse-query-params {:keywordizetrue})]}]})  start)

Server Examples

Consumes & Produces (seeRoutes section)

(->  (donkey/create-donkey)  (donkey/create-server    {:port8080:routes [{:path"/hello-world":methods      [:get]:handler-mode:blocking:consumes     ["text/plain"]:produces     ["application/json"]:handler      (fn [request]                               {:status200:body"{\"greet\":\"Hello world!\"}"})}]})  server/start)

Path variables (seeRoutes section)

(->  (donkey/create-donkey)  (donkey/create-server    {:port8080:routes [{:path"/greet/:name":methods  [:get]:consumes ["text/plain"]:handler  (fn [req respond _raise]                           (respond                             {:status200:headers {"content-type""text/plain"}:body    (str"Hello" (->:path-params req (get"name")))}))}]})  server/start)

Client

The following examples assume these required namespaces

(:require [com.appsflyer.donkey.core:as donkey]          [com.appsflyer.donkey.client:refer [request stop]]          [com.appsflyer.donkey.result:refer [on-complete on-success on-fail]]          [com.appsflyer.donkey.request:refer [submit submit-form submit-multipart-form]])

Creating a Client

Creating a client is as simple as this

(let [donkey-client (->                      (donkey/create-donkey)                       donkey/create-client)])

We can set up the client with some default options, so we won't need to supplythem on every request

(let [donkey-client (->                      (donkey/create-donkey)                       donkey/create-client                       {:default-host"reqres.in":default-port443:ssltrue:keep-alivetrue:keep-alive-timeout-seconds30:connect-timeout-seconds10:idle-timeout-seconds20:enable-user-agenttrue:user-agent"Donkey Server":compressiontrue})]    (-> donkey-client        (request {:method:get:uri"/api/users"})        submit        (on-complete           (fn [res ex]             (println (if ex"Failed!""Success!"))))))

The previous example made an HTTPS request to some REST api and printed out"Failed!" if an exception was received, or "Success!" if we got a response fromthe server. We'll discuss how submitting requests and handling responses workshortly.

Stopping a Client

Once we're done with a client we should always stop it. This will release allthe resources being held by the client, such as connections, event loops, etc'.You should reuse a single client throughout the lifetime of the application, andstop it only if it won't be used again. Once stopped it should not be usedagain.

(stop donkey-client)

Creating a Request

When creating a request we supply an options map that defines it. The map has tocontain a:method key, and either an:uri or an:url. The:uri keydefines the location of the resource being requested, for example:

(->   donkey-client  (request {:method:get:uri"/api/v1/users"}))

The:url key defines the absolute URL of the resource, for example:

(->   donkey-client  (request {:method:get:url"http://www.example.com/api/v1/users"}))

When an:url is supplied then the:uri,:port,:host and:sslkeys are ignored.

Submitting a Request

Calling(def async-request (request donkey-client opts)) creates anAsyncRequest but does not submit the request yet. You can reuse anAsyncRequest instance to make the same request multiple times. There areseveral ways a request can be submitted:

  • (submit async-request) submits a request without a body. This is usually thecase when doing aGET request.
  • (submit async-request body) submits a request with a raw body.body can beeither a string, or a byte array. A typical use case would bePOSTingserialized data such as JSON. Another common use case is sending binary databy also adding aContent-Type: application/octet-stream header to therequest.
  • (submit-form async-request body) submits an urlencoded form. AContent-Type: application/x-www-form-urlencoded header will be added to therequest, and the body will be urlencoded.body is a map of string key-valuepairs. For example, this is how you would typically submit a sign in form on awebsite:
(submit-form async-request {"email""frankies15@example.com""password""password"})
  • (submit-multipart-form async-request body) submits a multipart form. AContent-Type: multipart/form-data header will be added to the request.Multipart forms can be used to send simple key-value attribute pairs, anduploading files. For example, you can upload a file from the filesystem alongwith some attributes like this:
(submit-multipart-form   async-request     {"Lyrics""Phil Silvers""Music""Jimmy Van Heusen""Title""Nancy (with the Laughing Face)""Media Type""MP3""Media"      {"filename""nancy.mp3""pathname""/home/bill/Music/Sinatra/Best of Columbia/nancy.mp3""media-type""audio/mpeg""upload-as""binary"}})

FutureResult

Requests are submitted asynchronously, meaning the request is executed on abackground thread, and calls tosubmit[-xxx]* return aFutureResultimmediately. You can think of aFutureResult as a way to subscribe to an eventthat may have happened or will happen some time in the future. The api is verysimple:

  • (on-success async-result (fn [result])) will call the supplied function witha response map from the server, iff there were no client side errors whileexecuting the request. Client side errors include an unhandled exception, orproblems connecting with the server. It does not include server errors such as4xx or 5xx response status codes. The response will have the usual Ring fields:status,:body, and optional:headers.
  • (on-fail async-result (fn [ex])) will call the supplied function withanExceptionInfo indicating the request failed due to a client error.
  • (on-complete async-result (fn [result ex])) will always call the suppliedfunction whether the request was successful or not. A successful request willbe called withex beingnil, and a failed request will be calledwithresult beingnil. The two are mutually exclusive which makes itsimple to check the outcome of the request.

If the response is irrelevant as is the case in "call and forget" type requests,then the result can be ignored:

(submit async-request); => The `FutureResult` returned is ignored...do the rest of your application logic

Or if you are only interested to know if the request failed:

(->   (submit async-request)  (on-fail (fn [ex] (println (str"Oh, no. That was not expected -" (ex-message ex)))))...do the rest of your application logic

Although it is not recommended in the context of asynchronous operations,results can also be dereferenced:

(let [result @(submit async-request)]  (if (map? result)    (println"Yea!")    (println"Nay :(")))

In this case the call tosubmit will block the calling thread until a resultis available. The result may be either a response map, if the request wassuccessful, or anExceptionInfo if it wasn't.

Each function returns a newFutureResult instance, which makes it possible tochain handlers. Let's look at an example:

(nscom.appsflyer.donkey.exmaple  (:require [com.appsflyer.donkey.result:as result])  (:import (com.appsflyer.donkey FutureResult))); Chaning example. Each function gets the return value of the previous(letfn [(increment [val]                  (let [res (update val:count (fnil inc0))]                    (println res)                    res))]  (->    (FutureResult/create {})    (result/on-success increment)    (result/on-success increment)    (result/on-success increment)    (result/on-fail (fn [_ex] (println"We have a problem")))); Output:; {:count 1}; {:count 2}; {:count 3}

We start off by defining anincrement function that takes a map and incrementsa:counter key. We then create aFutureResult that completes with an emptymap. The first example shows how chaining the result of one function to the nextworks.


The rest of the examples assume the following vars are defined

(defdonkey-core (donkey/create-donkey))(defdonkey-client (donkey/create-client donkey-core)

HTTPS Requests

Making HTTPS requests requires setting:ssl totrue and:default-port or:port when creating a client or a request respectively.

(->  (request donkey-client {:host"reqres.in":port443:ssltrue:uri"/api/users?page=2":method:get})  submit  (on-success (fn [res] (println res)))  (on-fail (fn [ex] (println ex))));  Will output something like this:; `{:status 200,:headers {Age365, Access-Control-Allow-Origin *, CF-Cache-Status HIT, Via1.1 vegur, Set-Cookie __cfduid=1234.abcd; expires=Mon, 12-Oct-20 14:50:48 GMT; path=/; domain=.reqres.in; HttpOnly; SameSite=Lax; Secure, Date Sat, 12 Sep 2020 14:50:48 GMT, Accept-Ranges bytes, cf-request-id 0909abcd, Expect-CT max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct", Cache-Control max-age=14400, Content-Length 1245, Server cloudflare, Content-Type application/json; charset=utf-8, Connection keep-alive, Etag W/"4dd-IPv5LdOOb6s5S9E3i59wBCJ1k/0", X-Powered-By Express, CF-RAY 5d1a7165fa2cad73-TLV},:body #object[[B0x7be7d50c [B@7be7d50c]}`

Metrics

The library usesDropwizard to capturedifferent metrics. The metrics can be largely grouped into three categories:

  • Thread Pool
  • Server
  • Client

Metrics collection can be set up when creating aDonkey by supplying a preinstantiated instance ofMetricRegistry. It's the user's responsibility toimplement reporting to a monitoring backend suchasPrometheus, orgraphite. As later described, metrics are named using a dot. separator. By default,all metrics are prefixed withdonkey, but it's also possible to supplya:metrics-prefix with the:metric-registryto use a different string.

List of Exposed Metrics

Thread Pool Metrics

Base name:<:metrics-prefix>

  • event-loop-size - A Gauge of the number of threads in the event loop pool
  • worker-pool-size - A Gauge of the number of threads in the worker pool

Base name:<:metrics-prefix>.pools.worker.vert.x-worker-thread

  • queue-delay - A Timer measuring the duration of the delay to obtain theresource, i.e. the wait time in the queue
  • queue-size - A Counter of the actual number of waiters in the queue
  • usage - A Timer measuring the duration of the usage of the resource
  • in-use - A count of the actual number of resources used
  • pool-ratio - A ratio Gauge of the in use resource / pool size
  • max-pool-size - A Gauge of the max pool size

Server Metrics

Base name:<:metrics-prefix>.http.servers.<host>:<port>

  • open-netsockets - A Counter of the number of open net socket connections
  • open-netsockets.<remote-host> - A Counter of the number of open net socketconnections for a particular remote host
  • connections - A Timer of a connection and the rate of its occurrence
  • exceptions - A Counter of the number of exceptions
  • bytes-read - A Histogram of the number of bytes read.
  • bytes-written - A Histogram of the number of bytes written.
  • requests - A Throughput Timer of a request and the rate of it’s occurrence
  • <http-method>-requests - A Throughput Timer of a specific HTTP methodrequest, and the rate of its occurrence. Examples: get-requests, post-requests
  • responses-1xx - A ThroughputMeter of the 1xx response code
  • responses-2xx - A ThroughputMeter of the 2xx response code
  • responses-3xx - A ThroughputMeter of the 3xx response code
  • responses-4xx - A ThroughputMeter of the 4xx response code
  • responses-5xx - A ThroughputMeter of the 5xx response code

Client Metrics

Base name:<:metrics-prefix>.http.clients

  • open-netsockets - A Counter of the number of open net socket connections
  • open-netsockets.<remote-host> - A Counter of the number of open net socketconnections for a particular remote host
  • connections - A Timer of a connection and the rate of its occurrence
  • exceptions - A Counter of the number of exceptions
  • bytes-read - A Histogram of the number of bytes read.
  • bytes-written - A Histogram of the number of bytes written.
  • connections.max-pool-size - A Gauge of the max connection pool size
  • connections.pool-ratio - A ratio Gauge of the open connections / maxconnection pool size
  • responses-1xx - A Meter of the 1xx response code
  • responses-2xx - A Meter of the 2xx response code
  • responses-3xx - A Meter of the 3xx response code
  • responses-4xx - A Meter of the 4xx response code
  • responses-5xx - A Meter of the 5xx response code

Debug mode

Debug mode is activated when creating aDonkey with:debug true. In thismode several loggers are set to log at thetrace level. It means the logs willbevery verbose. For that reason it is not suitable for production use, andshould only be enabled in development as needed.

The logs include:

  • All of Netty's low level networking, system configuration, memory leakdetection logs and more.
  • Hexadecimal representation of each batch of packets being transmitted to aserver or from a client.
  • Request routing, which is useful to debug a route that is not being matched.
  • Donkey trace logs.

Logging

The library doesn't include any logging implementation, and can be used with anySLF4J compatible logging library. The exception is whenrunning indebug mode. In order to dynamically change the logging levelwithout forcing users to add XML configuration files, DonkeyusesLogback as its implementation. It should beincluded on the project's classpath, otherwise a warning will be printed anddebug logging will be disabled.

Troubleshooting

ClassNotFoundException - com.codahale.metrics.JmxAttributeGauge

Execution error (ClassNotFoundException) at jdk.internal.loader.BuiltinClassLoader/loadClass (BuiltinClassLoader.java:581). com.codahale.metrics.JmxAttributeGauge

Donkey has a transitive dependencyio.dropwizard.metrics/metrics-core version4.X.X. If you are using a library that is dependent on version 3.X.X then youcould get a dependency collision. To avoid it you can exclude the dependencywhen importing Donkey. For example:

project.clj

:dependencies [com.appsflyer/donkey"0.5.2":exclusions [io.dropwizard.metrics/metrics-core]]

deps.edn

{:deps {com.appsflyer/donkey {:mvn/version"0.5.2":exclusions [io.dropwizard.metrics/metrics-core]}}}

License

Copyright 2020 AppsFlyer

Licensed under the Apache License, Version 2.0 (the "License"); you may not usethis file except in compliance with the License. You may obtain a copy of theLicense athttp://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributedunder the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied. See the License for thespecific language governing permissions and limitations under the License.

About

Modern Clojure HTTP server and client built for ease of use and performance

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp