手动
手动插装是向应用程序添加可观察性代码的过程。
跟踪¶
初始化跟踪¶
To start tracing, you'll need to have an
initialized TracerProvider
that will let you create a Tracer
.
If a TracerProvider
is not created, the OpenTelemetry APIs for tracing will
use a no-op implementation and fail to generate data.
Node.js¶
To initialize tracing with the Node.js SDK, first ensure you have the SDK package and OpenTelemetry API installed:
Next, create a separate tracing.js|ts
file that has all the SDK initialization
code in it:
Next, ensure that tracing.js|ts
is required in your node invocation. This is
also required if you're registering instrumentation libraries. For example:
Browser¶
首先,确保你有正确的软件包:
Create a tracing.js|ts
file that initialized the Web SDK, creates a
TracerProvider
, and exports a Tracer
.
You'll need to bundle this file with your web application to be able to use tracing throughout the rest of your web application.
Picking the right span processor¶
By default, the Node SDK uses the BatchSpanProcessor
, and this span processor
is also chosen in the Web SDK example. The BatchSpanProcessor
processes spans
in batches before they are exported. This is usually the right processor to use
for an application.
In contrast, the SimpleSpanProcessor
processes spans as they are created. This
means that if you create 5 spans, each will be processed and exported before the
next span is created in code. This can be helpful in scenarios where you do not
want to risk losing a batch, or if you're experimenting with OpenTelemetry in
development. However, it also comes with potentially significant overhead,
especially if spans are being exported over a network - each time a call to
create a span is made, it would be processed and sent over a network before your
app's execution could continue.
In most cases, stick with BatchSpanProcessor
over SimpleSpanProcessor
.
Acquiring a tracer¶
Anywhere in your application where you write manual tracing code should call
getTracer
to acquire a tracer. For example:
It's generally recommended to call getTracer
in your app when you need it
rather than exporting the tracer
instance to the rest of your app. This helps
avoid trickier application load issues when other required dependencies are
involved.
创建 spans¶
Now that you have a Tracer
initialized, you can create Span
s.
The above code sample shows how to create an active span, which is the most common kind of span to create.
创建嵌套 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:
This code will create 3 child spans that have parentSpan
's span ID as their
parent IDs.
创建独立 spans¶
The previous examples showed how to create an active span. In some cases, you'll want to create inactive spans that are siblings of one another rather than being nested.
In this example, span1
, span2
, and span3
are sibling spans and none of
them are considered the currently active span. They share the same parent rather
than being nested under one another.
This arrangement can be helpful if you have units of work that are grouped together but are conceptually independent from one another.
获取当前 span¶
Sometimes it's helpful to do something with the current/active span at a particular point in program execution.
从上下文中获取 span¶
It can also be helpful to get the span from a given context that isn't necessarily the active span.
属性¶
Attributes let you attach key/value
pairs to a Span
so it carries more
information about the current operation that it's tracking.
You can also add attributes to a span as it's created:
语义属性¶
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. 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:
Add the following to the top of your application file:
Finally, you can update your file to include semantic attributes:
Span 事件¶
A Span Event is a human-readable
message on an Span
that represents a
discrete event with no duration that can be tracked by a single time stamp. You
can think of it like a primitive log.
You can also create Span Events with additional Attributes:
Span 链接¶
Span
s can be created with zero or more
Link
s to other Spans that are
causally related. A common scenario is to correlate one or more traces with the
current span.
Span 状态¶
A status can be set on a span,
typically used to specify that a span has not completed successfully -
SpanStatusCode.ERROR
.
The status can be set at any time before the span is finished:
By default, the status for all spans is Unset
rather than Ok
. It is
typically the job of another component in your telemetry pipeline to interpret
the Unset
status of a span, so it's best not to override this unless you're
explicitly tracking an error.
记录异常¶
It can be a good idea to record exceptions when they happen. It's recommended to do this in conjunction with setting span status.
Using sdk-trace-base
and manually propagating span context¶
In some cases, you may not be able to use either the Node.js SDK nor the Web SDK. The biggest difference, aside from initialization code, is that you'll have to manually set spans as active in the current context to be able to create nested spans.
使用sdk-trace-base
初始化跟踪¶
Initializing tracing is similar to how you'd do it with Node.js or the Web SDK.
Like the other examples in this document, this exports a tracer you can use throughout the app.
Creating nested spans with sdk-trace-base
¶
To create nested spans, you need to set whatever the currently-created span is
as the active span in the current context. Don't bother using startActiveSpan
because it won't do this for you.
All other APIs behave the same when you use sdk-trace-base
compared with the
Node.js or Web SDKs.
Metrics¶
To start metrics, you'll need to have an
initialized MeterProvider
that lets you create a Meter
. Meter
s let you
create Instrument
s that you can use to create different kinds of metrics.
OpenTelemetry JavaScript currently supports the following Instrument
s:
- Counter, a synchronous instrument which supports non-negative increments
- Asynchronous Counter, a asynchronous instrument which supports non-negative increments
- Histogram, a synchronous instrument which supports arbitrary values that are statistically meaningful, such as histograms, summaries or percentile
- Asynchronous Gauge, an asynchronous instrument which supports non-additive values, such as room temperature
- UpDownCounter, a synchronous instrument which supports increments and decrements, such as number of active requests
- Asynchronous UpDownCounter, an asynchronous instrument which supports increments and decrements
For more on synchronous and asynchronous instruments, and which kind is best suited for your use case, see Supplementary Guidelines.
If a MeterProvider
is not created either by an instrumentation library or
manually, the OpenTelemetry Metrics API will use a no-op implementation and fail
to generate data.
Initialize Metrics¶
To initialize metrics, make sure you have the right packages installed:
Next, create a separate instrumentation.js|ts
file that has all the SDK
initialization code in it:
You'll need to --require
this file when you run your app, such as:
Now that a MeterProvider
is configured, you can acquire a Meter
.
Acquiring a Meter¶
Anywhere in your application where you have manually instrumented code you can
call getMeter
to acquire a meter. For example:
It’s generally recommended to call getMeter
in your app when you need it
rather than exporting the meter instance to the rest of your app. This helps
avoid trickier application load issues when other required dependencies are
involved.
Synchronous and asynchronous instruments¶
OpenTelemetry instruments are either synchronous or asynchronous (observable).
Synchronous instruments take a measurement when they are called. The measurement is done as another call during program execution, just like any other function call. Periodically, the aggregation of these measurements is exported by a configured exporter. Because measurements are decoupled from exporting values, an export cycle may contain zero or multiple aggregated measurements.
Asynchronous instruments, on the other hand, provide a measurement at the request of the SDK. When the SDK exports, a callback that was provided to the instrument on creation is invoked. This callback provides the SDK with a measurement that is immediately exported. All measurements on asynchronous instruments are performed once per export cycle.
Asynchronous instruments are useful in several circumstances, such as:
- When updating a counter is not computationally cheap, and thus you don't want the currently executing thread to have to wait for that measurement
- Observations need to happen at frequencies unrelated to program execution (i.e., they cannot be accurately measured when tied to a request lifecycle)
- There is no value from knowing the precise timestamp of increments
In cases like these, it's often better to observe a cumulative value directly,
rather than aggregate a series of deltas in post-processing (the synchronous
example). Take note of the use of observe
rather than add
in the appropriate
code examples below.
Using Counters¶
Counters can by used to measure a non-negative, increasing value.
Using UpDown Counters¶
UpDown counters can increment and decrement, allowing you to observe a cumulative value that goes up or down.
Using Histograms¶
Histograms are used to measure a distribution of values over time.
For example, here's how you might report a distribution of response times for an API route with Express:
Using Observable (Async) Counters¶
Observable counters can be used to measure an additive, non-negative, monotonically increasing value.
Using Observable (Async) UpDown Counters¶
Observable UpDown counters can increment and decrement, allowing you to measure an additive, non-negative, non-monotonically increasing cumulative value.
Using Observable (Async) Gauges¶
Observable Gauges should be used to measure non-additive values.
Describing instruments¶
When you create instruments like counters, histograms, etc. you can give them a description.
In JavaScript, each configuration type means the following:
description
- a human-readable description for the instrumentunit
- The description of the unit of measure that the value is intended to represent. For example,milliseconds
to measure duration, orbytes
to count number of bytes.valueType
- The kind of numeric value used in measurements.
It's generally recommended to describe each instrument you create.
Adding attributes¶
You can add Attributes to metrics when they are generated.
Configure Metric Views¶
A Metric View provides developers with the ability to customize metrics exposed by the Metrics SDK.
Selectors¶
To instantiate a view, one must first select a target instrument. The following are valid selectors for metrics:
instrumentType
instrumentName
meterName
meterVersion
meterSchemaUrl
Selecting by instrumentName
(of type string) has support for wildcards, so you
can select all instruments using *
or select all instruments whose name starts
with http
by using http*
.
Examples¶
Filter attributes on all metric types:
Drop all instruments with the meter name pubsub
:
Define explicit bucket sizes for the Histogram named http.server.duration
:
Attach to meter provider¶
Once views have been configured, attach them to the corresponding meter provider:
Next steps¶
You'll also want to configure an appropriate exporter to export your telemetry data to one or more telemetry backends.