moleculer: Moleculer Datadog integration is not working
Prerequisites
Please answer the following questions for yourself before submitting an issue.
- I am running the latest version
- I checked the documentation and found no answer
- I checked to make sure that this issue has not already been filed
- I’m reporting the issue to the correct repository
Current Behavior
I should be able to get traces from my moleculer services on Datadog APM. I am using the latest version of Moleculer.
Expected Behavior
I do not get any Trace information. My moleculer service logs reports 400 bad request error. Correspondingly in the Datadog agent logs there are error messages stating trace payload could not be decoded.
Failure Information
The agent is version is v6.18.0 and the tracer version is 0.19.1.
I got the following in the moleculer service log:
Request to the agent: {"path":"/v0.4/traces","method":"PUT","headers":{"Content-Type":"application/msgpack","Datadog-Meta-Tracer-Version":"0.19.1","X-Datadog-Trace-Count":"2","Datadog-Meta-Lang":"nodejs","Datadog-Meta-Lang-Version":"v12.16.1","Datadog-Meta-Lang-Interpreter":"v8"},"protocol":"http:","hostname":"10.101.67.78","port":"8126"}
Error: Error from the agent: 400 Bad Request
at IncomingMessage.<anonymous> (/app/node_modules/dd-trace/packages/dd-trace/src/platform/node/request.js:35:23)
at IncomingMessage.emit (events.js:323:22)
at IncomingMessage.EventEmitter.emit (domain.js:482:12)
at endReadableNT (_stream_readable.js:1204:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
status: 400
}
I am getting the following in the Datadog agent log:
2020-04-23 03:31:25 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "array" with method for "str"
2020-04-23 03:31:33 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "int" with method for "str"
2020-04-23 03:31:35 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "int" with method for "str"
2020-04-23 03:31:43 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "int" with method for "str"
2020-04-23 03:31:45 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "int" with method for "str"
2020-04-23 03:31:53 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "map" with method for "str"
2020-04-23 03:31:55 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "map" with method for "str"
2020-04-23 03:32:03 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "map" with method for "str"
2020-04-23 03:32:05 UTC | TRACE | ERROR | (pkg/trace/api/api.go:379 in handleTraces) | Cannot decode v0.4 traces payload: msgp: attempted to decode type "int" with method for "str"
Steps to Reproduce
Please provide detailed steps for reproducing the issue.
-
I have created two env variables for the container running my moleculer service: DD_AGENT_HOST and DD_AGENT_URL. The service is able to connect to Datadog agent and sent tracing data.
-
I am initialising the service as:
"tracing": {
"enabled": true,
"events": true,
"stackTrace": true,
"exporter": {
"type": "Datadog",
"options": {
"tracerOptions": {
"analytics": true,
"debug": true,
"enabled": true,
"service": "my-service"
}
}
}
}
Reproduce code snippet
"tracing": {
"enabled": true,
"events": true,
"stackTrace": true,
"exporter": {
"type": "Datadog",
"options": {
"tracerOptions": {
"analytics": true,
"debug": true,
"enabled": true,
"service": "my-service"
}
}
}
}
Context
Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
- Moleculer version: 0.14.6
- NodeJS version: 10.15.3-alpine
- Operating System:
Failure Logs
See above
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 15 (8 by maintainers)
@icebob You mentioned several operations that are traced above. If you can link me to the code of one of them and also to how it’s currently traced I can try to do it using only our public interface if at all possible. If not, it will at least give me a better idea of how tracing works in Moleculer and what could be done to improve the interoperability.
@rochdev Yeah, this is currently a problem. The moleculer spans & datadog spans are not connected. The problem is that Moleculer is a full complex framework with a built-in tracing solution which monitors all services (actions, events, custom spans…etc). So you can’t create a dd-agent instrument for this, similar for express or redis where sufficient wrap some methods and the tracing will work.
In previous versions (maybe dd-trace 0.16) I’ve tried to make the connection between moleculer & datadog spans and it worked. I checked the full dd-trace source code and found the way how could I get the active span and how could I overwrite it from Moleculer (it was a dirty way because it uses private variables in dd-trace). But in the later dd-trace versions this internal things has been changed and this code stopped working. Here is a full trace from those times: You can see that the first span comes from DD-trace (http instrument) and there are Redis dd-trace spans between Moleculer spans.
In brief, I can solve it, if dd-trace would be two public methods. One method to get the current datadog span (trace_id & span_id & parent_span_id) based on the current
executionAsyncId
, and another method to set the current span (span_id & parent_span_id). Is there any chance that you can create them inside dd-trace?I’m seeing this issue too. I filed https://github.com/DataDog/dd-trace-js/issues/970, but after more investigation I believe the core problem is moleculer improperly setting IDs on the dd-trace spans. dd-trace’s MessagePack encoder expects the
traceId
andspanId
to be 8 bytes, because that’s what the id generator defaults to. However, moleculer overrides the dd-trace span’s generated IDs with the 16-byte GUIDs used by moleculer’s internal tracer. The extra bytes aren’t handled in the MessagePack encoding and it ends up corrupting the trace payload, resulting in decoding errors on the agent.In addition to corrupting the trace payload, it seems to also corrupt some internal state in dd-trace because future trace payloads will also be corrupt, even if their ids are the expected 8 bytes. I haven’t yet gone far enough to figure out why this happens.
(Related: #690. Perhaps these issues can be solved at the same time.)
Update:
I have tried this by doing activate in tracing middleware just before calling the actual handler and scope propagates fine. I am not sure yet how to do it for all of the exporters
datadog.js
(exporter)tracer.js (middleware)
CC: @icebob
@rochdev Great! In Moleculer there are actions and events. Both of them traced. Both have a
Context
instance which contains data for tracing, as well (id
,parentID
,requestID
).The built-in tracing feature is created as a middleware which can wrap the internal methods and can add additional functions. Here is the source of the tracing middleware
It wraps the service action & event handlers and generates tracing span based on the
Context
. It calls thectx.startSpan
andctx.finishSpan
methods which are a shorthand for theTracer
startSpan
&span.finish
The
Tracer
has exporters, it can be multiple. One of them the Datadog exporter which uses thedd-trace
to convert the Moleculer traces & spans to Datadog traces & spans.The developers can create custom spans as well. For this they call the
ctx.startSpan()
/ctx.finishSpan()
methods. Or if Context is not available,broker.tracer.startSpan()
/span.finish()
When a request goes from NodeA to NodeB via transporter, the trace info is carried with the
Context
to the remote node. All nodes collect the spans locally and send to the exportersHere is the simple generated demo where you can play with Moleculer: https://github.com/moleculerjs/project-demo
If you need any more info, just ask me.