A POC for the Java agent of Elastic APM
This is a proof of concept of Elastic APM Java agent implementation. It features automatic collection of errors and transactions for spring webmvc/spring boot web applications.
See https://github.com/elastic/apm-agent-java for the official java agent from Elastic.
It collects requests/errors, storing in two separate memory queues. Then every queue is monitored by a timer task, polling for new elements to send.
The model for documents (payloads) send to the APM server is automatically generated from APM json schema.
Try it with the sample sprig boot app, i.e. in order feed the apm server at http://localhost:8200 with data every 5 seconds
./gradlew assemble && ./gradlew "spring-boot-sample:bootRun" -Delastic.apm.period=5000
Then calling from command line
curl http://localhost:8080/
you will get a naive response: the transaction is automatically sent to the apm server
Call
curl http://localhost:8080/?fail=true
from command line to generate a fake exception and send it to the apm server.
❗
|
Please note that the APM server and Elasticsearch should be installed separately. |
Simply import the APM agent configuration
@SpringBootApplication
@Import (ApmConfiguration.class)
public class SpringBootSampleApplication {
...
}
then configure it as usual with properties, env vars or passing arguments at launch
- elastic.apm.host
-
The apm server base url Default:
http://localhost:8200
- elastic.apm.appname
-
Your app name Default:
MYAPP
- elastic.apm.secrettoken
-
Your app secret token Default:
MYSECRET
- elastic.apm.initialdelay
-
Initial delay before starting to send data to APM Default:
5000
- elastic.apm.period
-
Amount of millis between polls for new data to send Default:
1000
- elastic.apm.queue.capacity
-
Maximum data elements to stored in memory Default:
10000
- elastic.apm.queue.batchsize
-
Max elements drained from the memory in as single poll Default:
100
- elastic.apm.queue.enqueuetimeout
-
Max time to wait for memory to become available Default:
5000
💡
|
To specify environments variables convert props to uppercase and replace dots with underscores, i.e. elastic.apm.host becomes ELASTIC_APM_HOST
|
Inject the apm service, then call the traceError
or traceTransaction
where appropriate
...
@Autowired
private ApmSpringService apmSpringService;
// inside your logic
// let the agent populate data bits from your objects
...
apmSpringService.traceTransaction (request, response, status, duration);
} catch (final MyException e) {
apmSpringService.traceError (e, request, response);
}
...
// OR take full control of data sent, using fluent builders
// to prepare your own error/transaction objects
apmSpringService.traceTransaction (
new ApmTransaction()
.withId (id)
.withType ("request")
.withName (request.getURI())
.with...;
} catch (final MyException e) {
// or alternatively build your own error object
apmSpringService.traceError (
new ApmError()
.withId("myError123")
.withCulprit("the culprit you want")
.with...;
}
Plenty of things to do :-)
-
Add missing bits to transactions and errors generated payloads
-
Add missing config for generating transactions and errors
-
Define a widely acceptable sets of dependencies for generic agent/specific bindings (shading?)
-
Define a widely acceptable java version compatibility
-
Choose a logging library
-
Add support to gather jvm/system metrics (CPU, memory, threads)
-
Adopt a pluggable approach for queue consumers (supporting different threading models…)
-
Introduce support for other frameworks