@discue/open-telemetry-tracing
v1.3.0
Published
Simple scheduling and queueing
Downloads
384
Readme
open-telemetry-tracing
Kickstarts your OpenTelemetry implementation with first-class abstractions for
- adding tracing capabilities to NodeJS environments
- collecting and publishing of spans to local and cloud environments
- creating spans and child spans
- tracking successful completion of spans
- recording exceptions in case of errors during span execution
Setup
OpenTelemetry and its Instrumentations will inject tracing functionality into well-known and supported packages.
To enable tracing, the tracing runtime needs to be loaded before your application. To do so, set the NODE_OPTIONS
environment variable and require
the file node_modules/@discue/open-telemetry-tracing/lib/instrumentation.cjs
, which is the entry point for tracing.
NODE_OPTIONS=--require node_modules/@discue/open-telemetry-tracing/lib/instrumentation.cjs
Instrumentation
Instrumentations are the heart of tracing. Most of the tracing instrumentation is platform-agnostic. However, some parts of it can be platform-dependent.
This module features support for GCP and half-baked support for AWS (due to lack of usage of the platform in other projects). You can find the default instrumentations here:
If you feel instrumentations (or other features) are missing, please get in touch with us and / or open a PR 🙂.
How to create a span
Import the function createTracer
function.
import { createTracer } from '@discue/open-telemetry-tracing';
Call the function createTracer
and pass the filepath
to the current file as an optional parameter.
const { withActiveSpan } = createTracer({
filepath: import.meta.url
})
Wrap existing or new code inside a call to withActiveSpan
. You can add spanEvents
to add additional information for later analysis.
/**
*
* @param {_types.Request} req
* @param {_types.Response} res
* @param {Object} options
* @returns
*/
async handleRequest(req, res, { resourceIds }) {
// creates a new active span with name handle-delete-request
// will watch execution and record failures
//
// pass an object with additional attributes as second parameter
// to get more key value pairs added to the span
await withActiveSpan('handle-delete-request', async (span) => {
const resource = await this._service.get(resourceIds)
if (resource == null) {
// custom extension of the span with implementation-specific
// event and status
span.addEvent('Not found', { resourceIds })
.setStatus({ code: SpanStatusCode.ERROR })
return sendNotFound(res)
} else {
await this._service.delete(resourceIds)
sendOk({ req, res, body: {}, links: {} })
}
})
}
See a full implementation e.g. in @stfsy/api-kit/http-post-resource-endpoint.
How to create a span synchronously
To wrap a synchronous function inside a span, use the withActiveSpanSync
method. It also accepts a spanAttributes
object as optional second parameter.
import { createTracer } from '@discue/open-telemetry-tracing';
import { nanoid } from "nanoid";
const { withActiveSpanSync } = createTracer({
filepath: import.meta.url
})
/**
* Creates a url-safe resource id.
*
* @module newResourceId
* @returns {String}
*/
export const newResourceId = () => {
// wrap the sync call in a span and return the value
// that way the tracing is transparent for all callers
return withActiveSpanSync('create-resource-id', () => {
return nanoId()
})
}
See a full implementation e.g. in @stfsy/api-kit/resource-id.
How to create an orphaned span
That is a span that has no parent. Useful if you want to prevent deep nesting of spans. To create an orphan span call the withOrphanedSpan
method of the module. The spanAttributes
object is optional and can be omitted.
import { createTracer } from '@discue/open-telemetry-tracing';
import { SpanStatusCode } from '@opentelemetry/api';
const { withOrphanedSpan } = createTracer({
filepath: import.meta.url
})
const { method, headers } = request
const incomingContentType = headers['content-type'] ?? ''
const spanAttributes = { method, incomingContentType }
// checks whether the content type is set
// sets span status accordingly
// adds content-type as a span attribute so it can be queried via UI e.g. Jaeger
await withOrphanedSpan('check-content-type-is-set', spanAttributes, (span) => {
if (!incomingContentType ) {
span.addEvent('Check failed').setStatus({ code: SpanStatusCode.ERROR })
return sendUnsupportedMedia(response)
} else {
span.addEvent('Check succeeded').setStatus({ code: SpanStatusCode.OK })
}
return nextFunction()
})
See a full implementation e.g. in @stfsy/api-kit/content-type-middleware.
Configuration
The following environment variables can be set:
DSQ_OT_TRACING_SERVICE_NAME
- default: api-kit
DSQ_OT_LOCAL_OLTP_URL
- default: http://127.0.0.1:4318/v1/traces
- note: for cloud environments automatically, this library will configure the right exporter
DSQ_OT_USE_SIMPLE_SPAN_PROCESSOR
- default: false
DSQ_OT_ENABLE_DEBUG_LOGGING
- default: false
Exports
- /: The main export is the
createTracer
function. Import it via@discue/open-telemetry-tracing
to create traces as shown above. - /status-codes: Returns valid status codes a span can have. Use this expor to not couple your application to the Open Telemetry libraries. Use it via
@discue/open-telemetry-tracing/status-codes
. - /instrumentation: The
instrumentation
script needs to be loaded viaNODE_OPTIONS
function. This export is used internally via@discue/open-telemetry-tracing/instrumentation
to get ahold of the current tracer. Users of this library should not need to use this export.
Test
./test.sh