I am using elastic-apm-node agent to create distributed tracing.
Here is my services structures. I have 3 micro services.
producer, kafka, consumer
The call sequence is
producer -> kafka -> consumer
I am not using any auto instrument, I am using the elastic-apm-node-opentracing
, and I am using ipc to communicate between the services.
So here is my code to create the tracing.
- producer
const agent = require('elastic-apm-node').start({serviceName: 'serviceA'});
const tracer = new Tracer(agent);
const tran = tracer.startSpan('request051');
const span = tracer.startSpan('request5101', {references: [opentracing.followsFrom(tran.context())]});
ipc.connectTo('consumer', () => {
console.log('connected to consumer');
const headers = {};
tracer.inject(tran.context(), opentracing.FORMAT_HTT_HEADERS, headers);
ipc.sendTo('kafka', headers);
ipc.kafka.on('message', () => {
console.log('get response from kafka');
span.finish();
tran.finish();
});
});
- kafka
const agent = require('elastic-apm-node').start({serviceName: 'serviceA'});
const tracer = new Tracer(agent);
ipc.listen((message) => {
const ctx = tracer.extract(opentracing.FORMAT_HTTP_HEADERS, message);
const span = tracer.startSpan('kafka 51`, {childOf: ctx});
ipc.connectTo('consumer', () => {
ipc.consumer.on('message', () => {
span.finish();
ipc.sendTo('producer');
});
});
- consumer
ipc.listen((message) => {
const ctx = tracer.extract(opentracing.FORMAT_HTTP_HEADERS, message);
const span = tracer.startSpan('consumer 51`, {childOf: ctx});
ipc.sendTo('kafka');
span.finish();
});
So finally, the distributed tracing timeline looks like this.
Which looks correct, but the Service Map
has no links.
And I checked the source code of elastic-apm-node
apm-agent-nodejs/http-shared.js at master · elastic/apm-agent-nodejs · GitHub , to display the link of the Service Map
correctly, the destionationContext
and the httpContext
need to be set to the Span
(There is no documentation about this part, so I am not sure how to set this destination context correctly to do my own instrument). And this destination context
can be only set to the Span
object, and a Span
need to have an active
transaction, so I need to create a Transaction
and a Span
to display the link. So I am using some hacking way to make the link being displayed.
But since I have to create another transaction
for each span
, so the timeline looks like this.
You can see in the time line, there is a pair of transaction
and span
, they have the same duration, so the Transaction
is not really useful here, the purpose is just to display the links
of the Service Map.
To confirm my understanding about the ServiceMap
and the timeline
is correct, I am using opentracing
library with Jaeger
to display the timeline and the service dependency
.
And the code is the same with the elastic-apm-node-opentracing
code I post above.
The final result is:
So in the Elastic APM
, there are two concepts: Transaction
and Span
, and the Span
can not exist without a Transaction
, I think this is the key difference, but because of this concept, the behavior different between APM
and the opentracing
.
So I want to confirm my understanding is correct or not, and is that possible to be totally compatible with opentracing
to display service map correctly without additional Transaction
.
Thank you.