diff --git a/content/en/docs/instrumentation/js/instrumentation.md b/content/en/docs/instrumentation/js/instrumentation.md index 346ccc0264e8..237719b40497 100644 --- a/content/en/docs/instrumentation/js/instrumentation.md +++ b/content/en/docs/instrumentation/js/instrumentation.md @@ -3,7 +3,9 @@ title: Instrumentation weight: 3 --- -This guide will cover creating and annotating spans, creating and annotating metrics, how to pass context, and a guide to automatic instrumentation for JavaScript. This simple example works in the browser as well as with Node.js +This guide will cover creating and annotating spans, creating and annotating +metrics, how to pass context, and a guide to automatic instrumentation for +JavaScript. This simple example works in the browser as well as with Node.js ## Example Application @@ -25,29 +27,32 @@ function doWork() { ## Initializing a Tracer -As you have learned in the previous [Getting Started](../getting-started) guide you -need a TracerProvider and an Exporter. Install the dependencies and add them to -the head of your application code to get started: +As you have learned in the previous [Getting Started](../getting-started) guide +you need a TracerProvider and an Exporter. Install the dependencies and add them +to the head of your application code to get started: ```shell npm install @opentelemetry/api npm install @opentelemetry/sdk-trace-base ``` -Next, initialize a tracer, preferably in a separate file (e.g., `instrumentation-setup.js`): +Next, initialize a tracer, preferably in a separate file (e.g., +`instrumentation-setup.js`): ```javascript const { BasicTracerProvider, ConsoleSpanExporter, - SimpleSpanProcessor, + BatchSpanProcessor, } = require('@opentelemetry/sdk-trace-base'); const opentelemetry = require('@opentelemetry/api'); const provider = new BasicTracerProvider(); // Configure span processor to send spans to the exporter -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const exporter = new ConsoleSpanExporter() +const processor = new BatchSpanProcessor(exporter) +provider.addSpanProcessor(processor); provider.register(); // This is what we'll access in all instrumentation code @@ -56,9 +61,11 @@ export const tracer = opentelemetry.trace.getTracer( ); ``` -This registers a tracer provider with the OpenTelemetry API as the global tracer provider, and exports a tracer instance that you can use to create spans. +This registers a tracer provider with the OpenTelemetry API as the global tracer +provider, and exports a tracer instance that you can use to create spans. -If you do not register a global tracer provider, any instrumentation calls will be a no-op, so this is important to do! +If you do not register a global tracer provider, any instrumentation calls will +be a no-op, so this is important to do! ## Create spans @@ -93,25 +100,30 @@ Run your application and you will see traces being exported to the console: ## Create nested spans -Nested spans let you track work that's nested in nature. For example, the `doWork` function below represents a nested operation. The following sample creates a nested span that tracks the `doWork` function: +Nested spans let you track work that's nested in nature. For example, the +`doWork` function below represents a nested operation. The following sample +creates a nested span that tracks the `doWork` function: ```javascript -// Create a span. A span must be closed. -const parentSpan = tracer.startSpan('main'); -for (let i = 0; i < 10; i += 1) { - doWork(parentSpan); -} +const mainWork = () => { + const parentSpan = tracer.startSpan('main'); + + for (let i = 0; i < 3; i += 1) { + doWork(parentSpan, i); + } -/* ... */ + // Be sure to end the parent span! + parentSpan.end(); +} -function doWork(parent) { - // Start another span. In this example, the main function already started a - // span, so that'll be the parent span, and this will be a child span. +function doWork(parent, i) { + // To set a child span, we need to mark the parent span as the active span + // in the context, then use the resulting context to create a child span. const ctx = opentelemetry.trace.setSpan( opentelemetry.context.active(), parent ); - const span = tracer.startSpan('doWork', undefined, ctx); + const span = tracer.startSpan(`doWork:${i}`, undefined, ctx); // simulate some random work. for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { @@ -122,16 +134,15 @@ function doWork(parent) { // it will continue to track work beyond 'doWork'! span.end(); } - -// Be sure to end the parent span. -parentSpan.end(); ``` -If you run the application again, you'll see the parent span and then a span for each call to `doWork`, each listing `parentSpan`'s ID as its `parentId`. +This code will create 3 child spans that have `parentSpan`'s span ID as their +parent IDs. ## Get the current span -Sometimes it's helpful to do something with the current/active span at a particular point in program execution. +Sometimes it's helpful to do something with the current/active span at a +particular point in program execution. ```js const span = opentelemetry.trace.getSpan(opentelemetry.context.active()); @@ -141,37 +152,30 @@ const span = opentelemetry.trace.getSpan(opentelemetry.context.active()); ## Attributes -Attributes can be used to describe your spans. Attributes can be added to a span at any time before the span is finished: +Attributes can be used to describe your spans. Attributes can be added to a span +at any time before the span is finished: ```javascript -function doWork(parent) { - const ctx = opentelemetry.trace.setSpan( - opentelemetry.context.active(), - parent - ); - - // Add an attribute to a span at the time of creation - const span = tracer.startSpan( - 'doWork', - { attributes: { attribute1: 'value1' } }, - ctx - ); - - for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { - // empty - } +const span = tracer.startSpan( + 'app.new-span', + { attributes: { attribute1: 'value1' } }, + ctx +); - // Add an attribute to the same span later on - span.setAttribute('attribute2', 'value2'); +// Add an attribute to the same span later on +span.setAttribute('attribute2', 'value2'); - // Be sure to end the span! - span.end(); -} +// Make sure to end the span if you're done with it! +span.end(); ``` ### Semantic Attributes -There are semantic conventions for spans representing operations in well-known protocols like HTTP or database calls. Semantic conventions for these spans are defined in the specification at [Trace Semantic Conventions]({{< relref "/docs/reference/specification/trace/semantic_conventions" >}}). In the simple example of this guide the source code attributes can be used. +There are semantic conventions for spans representing operations in well-known +protocols like HTTP or database calls. Semantic conventions for these spans are +defined in the specification at [Trace Semantic Conventions]({{< relref +"/docs/reference/specification/trace/semantic_conventions" >}}). In the simple +example of this guide the source code attributes can be used. First add the semantic conventions as a dependency to your application: @@ -188,27 +192,26 @@ const { SemanticAttributes } = require('@opentelemetry/semantic-conventions'); Finally, you can update your file to include semantic attributes: ```javascript -function doWork(parent) { - const ctx = opentelemetry.trace.setSpan( - opentelemetry.context.active(), - parent - ); +const doWork = () => { const span = tracer.startSpan( - 'doWork', + 'app.new-span', { attributes: { [SemanticAttributes.CODE_FUNCTION]: 'doWork' } }, ctx ); - for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { - // empty - } + + // Add an attribute to the same span later on span.setAttribute(SemanticAttributes.CODE_FILEPATH, __filename); + + // Make sure to end the span if you're done with it! span.end(); } ``` ## Span events -An event is a human-readable message attached to a span that represents "something happening" during its lifetime. You can think of it like a primitive log. +An event is a human-readable message attached to a span that represents +"something happening" during its lifetime. You can think of it like a primitive +log. ```js span.addEvent('Doing something'); @@ -252,37 +255,31 @@ function someFunction(spanToLinkFrom) { ## Span Status -A status can be set on a span, typically to indicate that it did not complete -successuflly - `SpanStatusCode.ERROR`. In rare situations, you may wish to -override this with `SpanStatusCode.OK`. But don't set the status to `OK` -each time a span successfully completes. - -The status can be set at any time before the span is finished: +A status can be set on a span, typically used to specify that there was an error +in the operation a span is tracking - .`Error`. ```javascript -function doWork(parent) { - const ctx = opentelemetry.trace.setSpan( - opentelemetry.context.active(), - parent - ); - const span = tracer.startSpan('doWork', undefined, ctx); - - for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { - if (i > 10000) { - span.setStatus({ - code: opentelemetry.SpanStatusCode.ERROR, - message: 'Error' - }); - } +const span = tracer.startSpan('doWork', undefined, ctx); + +for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { + if (i > 10000) { + span.setStatus({ + code: opentelemetry.SpanStatusCode.ERROR, + message: 'Error' + }); } - - span.end(); } + +span.end(); ``` +By default, the status for all spans is `Unset`. In rare cases, you may also +wish to set the status to `Ok`. This should generally not be necessary, though. + ## Recording exceptions -It can be a good idea to record exceptions when they happen. It's recommended to do this in conjunction with setting [span status](#span-status). +It can be a good idea to record exceptions when they happen. It's recommended to +do this in conjunction with setting [span status](#span-status). ```js try {