| Title: | OpenTelemetry R API |
|---|---|
| Description: | High-quality, ubiquitous, and portable telemetry to enable effective observability. OpenTelemetry is a collection of tools, APIs, and SDKs used to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior. This package implements the OpenTelemetry API: <https://opentelemetry.io/docs/specs/otel/>. Use this package as a dependency if you want to instrument your R package for OpenTelemetry. |
| Authors: | Gábor Csárdi [aut, cre] |
| Maintainer: | Gábor Csárdi <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0.9000 |
| Built: | 2026-05-08 07:31:14 UTC |
| Source: | https://github.com/r-lib/otel |
Convert a list of R objects to a form that is suitable as OpenTelemetry attributes.
as_attributes(x)as_attributes(x)
x |
A list of R objects, to be used as OpenTelemetry attributes. |
A named list that can be used as the attributes argument to
the start_span() method of otel_tracer, the log() method of
otel_logger, etc.
If x is not named, or some names are the empty string or NA, then
integer numbers as used for the missing or invalid names.
If some elements in x are not of the natively supported R types in
OpenTelemetry (character, logical, double, integer), then
their printed form is captured using utils::capture.output().
The number of attributes can be limited with the OTEL_ATTRIBUTE_COUNT_LIMIT environment variable. The default is 128.
The length of the each attribute (vector) can be limited with the
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT environment variable. The default is
Inf. Note that this is applied to
the length of each attribute as an R vector. E.g. it does not
currently limit the number of characters in individual strings.
as_attributes(list( number = 1.0, vector = 1:10, string = "otel", string_vector = letters, object = mtcars ))as_attributes(list( number = 1.0, vector = 1:10, string = "otel", string_vector = letters, object = mtcars ))
Increase an OpenTelemetry counter
counter_add(name, value = 1L, attributes = NULL, context = NULL, meter = NULL)counter_add(name, value = 1L, attributes = NULL, context = NULL, meter = NULL)
name |
Name of the counter. |
value |
Value to add to the counter, defaults to 1. |
attributes |
Additional attributes to add. |
context |
Span context. If missing the active context is used, if any. |
meter |
Meter object (otel_meter). Otherwise it is passed to
|
The counter object (otel_counter), invisibly.
Other OpenTelemetry metrics instruments:
gauge_record(),
histogram_record(),
up_down_counter_add()
Other OpenTelemetry metrics API:
gauge_record(),
histogram_record(),
is_measuring_enabled(),
up_down_counter_add()
otel::counter_add("total-session-count", 1)otel::counter_add("total-session-count", 1)
Exporters, like the ones in the otelsdk package, can use this function to determine the default tracer name, if the instrumentation author hasn't specified one. If you are an instrumentation author, you probably do not need to call this function directly, but do read on to learn about choosing and setting the tracer name.
default_tracer_name(name = NULL)default_tracer_name(name = NULL)
name |
Custom tracer name. If |
The name of a tracer identifies an OpenTelemetry instrumentation scope. Instrumentation scopes can be used to organize the collected telemetry data. otel can also use instrumentation scopes to suppress emitting unneeded telemetry data, see 'Environment Variables'.
For the otel R package it makes sense to create a separate instrumentation scope for each R package that emits telemetry data. otel can do this automatically, with some from the package author.
As a package author, you can define the otel_tracer_name symbol in
your package and set it do the desired tracer name. For example, the
callr package has this in an .R file:
otel_tracer_name <- "org.r-lib.callr"
See below for tips on choosing a tracer name.
If you don't like the default tracer name, you can call get_tracer()
(or get_logger() or get_meter() manually with the desired name.
This is the detailed algorithm that otel uses in default_tracer_name:
Using base::topenv() it finds the calling package (or other top
level environment), recursively.
It ignores the otel and otelsdk packages while searching.
If it finds the base environment or the global environment, then
it checks for the otel_tracer_name global variable (in the global
environment). If that exists, then it must be a scalar string and it
is used as the tracer name. Otherwise org.project.R is used as the
tracer name.
Otherwise it looks for the otel_tracer_name symbol inside the top
level environment it has found. If this symbol exists then it must be
a string scalar and otel will use it as the tracer name.
If this symbol does not exist, then otel will use
r.package.<environment-name> as the tracer name.
<environment-name> is usually the package name.
The OpenTelemetry specification recommends using a tracer name that identifies the instrumentation scope, i.e. your package.
Some tips on choosing the tracer name:
If your R package can be associated with a URL, you can use the
"reverse" of that URL. E.g. since the callr package's online manual
is at https://callr.r-lib.org, it can use org.r-lib.callr.
If your R package belongs to your company, you can use the "reverse"
of the company URL, possibly with an additional prefix. E.g. for the
shiny R package by Posit, co.posit.r-package.shiny seems like a
good name.
If you don't set otel_tracer_name, then default_tracer_name will
use r.package.<package-name> as the tracer name.
A list with entries:
name: The supplied or auto-detected tracer name.
package: Auto-detected package name or NA.
on: Whether tracing is enabled for this package.
default_tracer_name()default_tracer_name()
Spans created with start_local_active_span() end automatically by
default. You must end every other span manually, by calling end_span,
or using the end_on_exit argument of local_active_span() or
with_active_span().
end_span(span)end_span(span)
span |
The span to end. |
Nothing.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
is_tracing_enabled(),
local_active_span(),
start_local_active_span(),
start_span(),
tracing-constants,
with_active_span()
fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()
This manual page contains the environment variables you can use to configure the otel package.
See also the Environment Variables in the otelsdk package, which is charge of the data collection configuration.
You need set these environment variables when configuring the collection of telemetry data, unless noted otherwise.
Not applicable.
OTEL_ENV
By default otel runs in production mode. In production mode otel functions never error. Errors in the telemetry code will not stop the monitored application.
This behavior is not ideal for development, where one would prefer to catch errors early. Set
OTEL_ENV=dev
to run otel in development mode, where otel functions fail on error, make it easier to fix errors.
otel is responsible for selecting the providers to use for traces, logs and metrics. You can use the environment variables below to point the otel functions to the desired providers.
If none of these environment variables are set, then otel will not emit any telemetry data.
OTEL_TRACES_EXPORTER
The name of the selected tracer provider. See
get_default_tracer_provider() for the possible values.
OTEL_R_TRACES_EXPORTER
R specific version of OTEL_TRACES_EXPORTER.
OTEL_LOGS_EXPORTER
The name of the selected logger provider. See
get_default_logger_provider() for the possible values.
OTEL_R_LOGS_EXPORTER
R specific version of OTEL_LOGS_EXPORTER.
OTEL_METRICS_EXPORTER
The name of the selected meter provider. See
get_default_meter_provider() for the possible values.
OTEL_R_METRICS_EXPORTER
R specific version of OTEL_METRICS_EXPORTER.
otel has two environment variables to fine tune which instrumentation scopes (i.e. R packages, typically) emit telemetry data. By default, i.e. if neither of these are set, all packages emit telemetry data.
OTEL_R_EMIT_SCOPES
Set this environment variable to a comma separated string of
instrumentation scope names or R package names to restrict telemetry to
these packages only. The name of the instrumentation scope is the same
as the name of the tracer, logger or meter, see default_tracer_name().
You can mix package names and instrumentation scope names and you can also use wildcards (globbing). For example the value
OTEL_R_EMIT_SCOPES="org.r-lib.*,dplyr"
selects all packages with an instrumentation scope that starts with
org.r-lib. and also dplyr.
OTEL_R_SUPPRESS_SCOPES
Set this environment variable to a comma separated string of
instrumentation scope names or R package names to suppress telemetry
data from these packages. The name of the instrumentation scope is the same
as the name of the tracer, logger or meter, see default_tracer_name().
You can mix package names and instrumentation scope names and you can also use wildcards (globbing). For example the value
OTEL_R_SUPPRESS_SCOPES="org.r-lib.*,dplyr"
excludes packages with an instrumentation scope that starts with
org.r-lib. and also dplyr.
otel can instrument R packages for OpenTelemetry data collection
without changing their source code. This relies on changing the code
of the R functions manually using base::trace() and can be configured
using environment variables.
OTEL_R_INSTRUMENT_PKGS
Set OTEL_R_INSTRUMENT_PKGS to a comma separated list of packages to
instrument. The automatic instrumentation happens when the otel package
is loaded, so in general it is best to set this environment variable
before loading R.
OTEL_R_INSTRUMENT_PKGS_<pkg>_INCLUDE
For an automatically instrumented package, set this environment variable
to only instrument a subset of its functions. It is parsed as a comma
separated string of function names, which may also include ? and *
wildcards (globbing).
OTEL_R_INSTRUMENT_PKGS_<pkg>_EXCLUDE
For an automatically instrumented package, set this environment variable
to exclude some functions from instrumentation. It has the same syntax
as its *_INCLUDE pair. If both are set, then inclusion is applied
and the exclusion.
OTEL_ATTRIBUTE_COUNT_LIMIT
Set this environment variable to limit the number of attributes for a
single span, log record, metric measurement, etc. If unset, the default
limit is 128 attributes.
Note that only attributes specified with as_attributes() are
subject to this environment variable.
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT
Set this environment variable to limit the length of vectors in
attributes for a single span, log record, metric measurement, etc.
If unset, there is no limit on the lengths of vectors in attributes.
Note that only attributes specified with as_attributes() are
subject to this environment variable.
Environment Variables in otelsdk
# To start an R session using the OTLP exporter: # OTEL_TRACES_EXPORTER=http R -q -f script.R# To start an R session using the OTLP exporter: # OTEL_TRACES_EXPORTER=http R -q -f script.R
The return value can be used as the parent option when starting
a span.
extract_http_context(headers)extract_http_context(headers)
headers |
A named list with one or two strings: |
And otel_span_context object.
hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid()hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid()
Record a value of an OpenTelemetry gauge
gauge_record(name, value, attributes = NULL, context = NULL, meter = NULL)gauge_record(name, value, attributes = NULL, context = NULL, meter = NULL)
name |
Name of the gauge |
value |
Value to record. |
attributes |
Additional attributes to add. |
context |
Span context. If missing the active context is used, if any. |
meter |
Meter object (otel_meter). Otherwise it is passed to
|
The gauge object (otel_gauge), invisibly.
Other OpenTelemetry metrics instruments:
counter_add(),
histogram_record(),
up_down_counter_add()
Other OpenTelemetry metrics API:
counter_add(),
histogram_record(),
is_measuring_enabled(),
up_down_counter_add()
otel::gauge_record("temperature", 27)otel::gauge_record("temperature", 27)
This is sometimes useful, to add additional attributes or links to the currently active span.
get_active_span()get_active_span()
The active span, an otel_span object, if any, or an invalid span if there is no active span.
fun <- function() { otel::start_local_active_span("fun") spn <- otel::get_active_span() spn$set_attribute("key", "attribute-value") } fun()fun <- function() { otel::start_local_active_span("fun") spn <- otel::get_active_span() spn$set_attribute("key", "attribute-value") } fun()
This is sometimes useful for logs or metrics, to associate logging and metrics reporting with traces.
get_active_span_context()get_active_span_context()
Note that logs and metrics instruments automatically use the current span context, so often you don't need to call this function explicitly.
The active span context, an otel_span_context object.
If there is no active span context, then an invalid span context is
returned, i.e. spc$is_valid() will be FALSE for the returned spc.
fun <- function() { otel::start_local_active_span("fun") fun2() } fun2 <- function() { otel::log("Log message", span_context = otel::get_active_span_context()) } fun()fun <- function() { otel::start_local_active_span("fun") fun2() } fun2 <- function() { otel::log("Log message", span_context = otel::get_active_span_context()) } fun()
The logger provider defines how logs are exported when collecting telemetry data. It is unlikely that you need to call this function directly, but read on to learn how to configure which exporter to use.
get_default_logger_provider()get_default_logger_provider()
If there is no default set currently, then it creates and sets a default.
The default logger provider is created based on the OTEL_R_LOGS_EXPORTER environment variable. This environment variable is specifically for R applications with OpenTelemetry support.
If this is not set, then the generic OTEL_LOGS_EXPORTER environment variable is used. This applies to all applications that support OpenTelemetry and use the OpenTelemetry SDK.
The following values are allowed:
none: no traces are exported.
stdout or console: uses otelsdk::logger_provider_stdstream,
to write traces to the standard output.
stderr: uses otelsdk::logger_provider_stdstream, to write traces
to the standard error.
http or otlp: uses otelsdk::logger_provider_http, to send
traces through HTTP, using the OpenTelemetry Protocol (OTLP).
otlp/file uses otelsdk::logger_provider_file to write logs
to a JSONL file.
<package>::<provider>: will select the <provider> object from
the <package> package to use as a logger provider. It calls
<package>::<provider>$new() to create the new logger provider.
If this fails for some reason, e.g. the package is not installed,
then it throws an error.
The default logger provider, an otel_logger_provider object.
Other low level logs API:
get_logger(),
logger_provider_noop,
otel_logger,
otel_logger_provider
get_default_logger_provider()get_default_logger_provider()
The meter provider defines how metrics are exported when collecting telemetry data. It is unlikely that you need to call this function directly, but read on to learn how to configure which exporter to use.
get_default_meter_provider()get_default_meter_provider()
If there is no default set currently, then it creates and sets a default.
The default meter provider is created based on the OTEL_R_METRICS_EXPORTER environment variable. This environment variable is specifically for R applications with OpenTelemetry support.
If this is not set, then the generic OTEL_METRICS_EXPORTER environment variable is used. This applies to all applications that support OpenTelemetry and use the OpenTelemetry SDK.
The following values are allowed:
none: no metrics are exported.
stdout or console: uses otelsdk::meter_provider_stdstream,
to write metrics to the standard output.
stderr: uses otelsdk::meter_provider_stdstream, to write
metrics to the standard error.
http or otlp: uses otelsdk::meter_provider_http, to send
metrics through HTTP, using the OpenTelemetry Protocol (OTLP).
otlp/file uses otelsdk::meter_provider_file to write metrics
to a JSONL file.
<package>::<provider>: will select the <provider> object from
the <package> package to use as a meter provider. It calls
<package>::<provider>$new() to create the new meter provider.
If this fails for some reason, e.g. the package is not installed,
then it throws an error.
The default meter provider, an otel_meter_provider object.
Other low level metrics API:
get_meter(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_histogram,
otel_meter,
otel_meter_provider,
otel_up_down_counter
get_default_meter_provider()get_default_meter_provider()
The tracer provider defines how traces are exported when collecting telemetry data. It is unlikely that you need to call this function directly, but read on to learn how to configure which exporter to use.
get_default_tracer_provider()get_default_tracer_provider()
If there is no default set currently, then it creates and sets a default.
The default tracer provider is created based on the OTEL_R_TRACES_EXPORTER environment variable. This environment variable is specifically for R applications with OpenTelemetry support.
If this is not set, then the generic OTEL_TRACES_EXPORTER environment variable is used. This applies to all applications that support OpenTelemetry and use the OpenTelemetry SDK.
The following values are allowed:
none: no traces are exported.
stdout or console: uses otelsdk::tracer_provider_stdstream,
to write traces to the standard output.
stderr: uses otelsdk::tracer_provider_stdstream, to write traces
to the standard error.
http or otlp: uses otelsdk::tracer_provider_http, to send
traces through HTTP, using the OpenTelemetry Protocol (OTLP).
otlp/file uses otelsdk::tracer_provider_file to write traces
to a JSONL file.
<package>::<provider>: will select the <provider> object from
the <package> package to use as a tracer provider. It calls
<package>::<provider>$new() to create the new tracer provider.
If this fails for some reason, e.g. the package is not installed,
then it throws an error.
The default tracer provider, an otel_tracer_provider object. See otel_tracer_provider for its methods.
Other low level trace API:
get_tracer(),
otel_span,
otel_span_context,
otel_tracer,
otel_tracer_provider,
tracer_provider_noop
get_default_tracer_provider()get_default_tracer_provider()
Get a logger from the default logger provider
get_logger( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )get_logger( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )
name |
Name of the new tracer. If missing, then deduced automatically. |
minimum_severity |
A log level, the minimum severity log messages to log. See log_severity_levels. |
version |
Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: |
schema_url |
Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. |
attributes |
Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. |
... |
Additional arguments are passed to the |
provider |
Tracer provider to use. If |
An otel_logger object.
Other low level logs API:
get_default_logger_provider(),
logger_provider_noop,
otel_logger,
otel_logger_provider
myfun <- function() { lgr <- otel::get_logger() otel::log("Log message", logger = lgr) } myfun()myfun <- function() { lgr <- otel::get_logger() otel::log("Log message", logger = lgr) } myfun()
Get a meter from the default meter provider
get_meter( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )get_meter( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )
name |
Name of the new tracer. If missing, then deduced automatically. |
version |
Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: |
schema_url |
Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. |
attributes |
Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. |
... |
Additional arguments are passed to the |
provider |
Meter provider to use. If |
An otel_meter object.
Other low level metrics API:
get_default_meter_provider(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_histogram,
otel_meter,
otel_meter_provider,
otel_up_down_counter
myfun <- function() { mtr <- otel::get_meter() ctr <- mtr$create_counter("session-count") ctr$add(1) } myfun()myfun <- function() { mtr <- otel::get_meter() ctr <- mtr$create_counter("session-count") ctr$add(1) } myfun()
Calls get_default_tracer_provider() to get the default tracer
provider. Then calls its $get_tracer() method to create a new tracer.
get_tracer( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )get_tracer( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL )
name |
Name of the new tracer. If missing, then deduced
automatically using |
version |
Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: |
schema_url |
Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. |
attributes |
Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. |
... |
Additional arguments are passed to the |
provider |
Tracer provider to use. If |
Usually you do not need to call this function directly, because
start_local_active_span() calls it for you.
Calling get_tracer() multiple times with the same name (or same
auto-deduced name) will return the same (internal) tracer object.
(Even if the R external pointer objects representing them are
different.)
A tracer is only deleted if its tracer provider is deleted and garbage collected.
An OpenTelemetry tracer, an otel_tracer object.
Other low level trace API:
get_default_tracer_provider(),
otel_span,
otel_span_context,
otel_tracer,
otel_tracer_provider,
tracer_provider_noop
myfun <- function() { trc <- otel::get_tracer() spn <- trc$start_span() on.exit(otel::end_span(spn), add = TRUE) otel::local_active_span(spn, end_on_exit = TRUE) } myfun()myfun <- function() { trc <- otel::get_tracer() spn <- trc$start_span() on.exit(otel::end_span(spn), add = TRUE) otel::local_active_span(spn, end_on_exit = TRUE) } myfun()
This page is about instrumenting you R package or project for OpenTelemetry. If you want to start collecting OpenTelemetry data for instrumented packages, see Collecting Telemetry Data in the otelsdk package.
OpenTelemetry is an observability framework. OpenTelemetry is a collection of tools, APIs, and SDKs used to instrument, generate, collect, and export telemetry data such as metrics, logs, and traces, for analysis in order to understand your software’s performance and behavior.
For an introduction to OpenTelemetry, see the OpenTelemetry website docs.
Use the otel package as a dependency if you want to instrument your R package or project for OpenTelemetry.
Use the otelsdk package to produce OpenTelemetry output from an R package or project that was instrumented with the otel package.
To instrument your package with otel, you need to do a couple of steps. In this section we show how to instrument the callr package.
The first step is to add the otel package as a dependency. otel is a very
lightweight package, so may want to add it as a hard dependency. This has
the advantage that you don't need to check if otel is installed every time
you call an otel function. Add otel to the Imports section in
DESCRIPTION:
Imports:
otel
Alternatively, you may add otel as a soft dependency. Add otel to the
Suggests section in DESCRIPTION:
Suggests:
otel
If you add otel in Suggests, then it makes sense to create a helper
function that checks if otel is installed and also that tracing is enabled
for the caller. You can put this function in any R file, e.g. R/utils.R
is a nice place for it:
is_otel_tracing <- function() {
requireNamespace("otel", quietly = TRUE) && otel::is_tracing_enabled()
}
Every package should have its own tracer with a name that is unique for the
package. See default_tracer_name() for tips on choosing a good tracer
name. Set the otel_tracer_name variable to the tracer name. No need to
export this symbol. In callr, we'll add
otel_tracer_name <- "org.r-lib.callr"
to the R/callr-package.R file.
Select the functions you want to add tracing to. It is overkill to add tracing to small functions that are called lots of times. It makes sense to add spans to the main functions of the package.
The callr package has various ways of starting another R process and then running R code in it. We'll add tracing to the
callr::r()
callr::rcmd()
callr::rscript()
functions first.
We add to callr::r() in eval.R:
if (is_otel_tracing()) {
otel::start_local_active_span(
"callr::r",
attributes = otel::as_attributes(options)
)
}
We use the is_otel_tracing() helper function, defined above.
start_local_active_span() starts a span and also activates it.
It also sets up an exit handler that ends the span when the caller
function (callr::r()) exits.
options contain a long list of user-provided and other option, we
add these to the span as attributes.
We add essentially the same code to callr::rcmd():
if (is_otel_tracing()) {
otel::start_local_active_span(
"callr::rcmd",
attributes = otel::as_attributes(options)
)
}
And to callr::rscript():
if (is_otel_tracing()) {
otel::start_local_active_span(
"callr::rscript",
attributes = otel::as_attributes(options)
)
}
An instance of the callr::r_session R6 class represents persistent
R background processes. We want to collect all spans from an R process into
the same trace. Since the R processes are running concurrently, their
(sub)spans will not form the correct hierarchy if we use the default,
timing-based otel mechanism to organize spans into trees. We need to
manage the lifetime and activation of the spans that represent the R
processes manually.
A generic strategy for handling concurrency in otel is:
Create a new long lasting span with start_span().
(I.e. not start_local_active_span()!)
Assign the returned span into the corresponding object of the concurrent and/or asynchronous computation. Every span has a finalizer that closes the span.
When running code that belongs to the concurrent computation represented
by the span, activate it for a specific R scope by calling
with_active_span() or local_active_span().
When the concurrent computation ends, close the span manually
with its $end() method or end_span(). (Otherwise it would be only
closed at the next garbage collection, assuming there are no references
to it.)
This code goes into the constructor of the r_session object:
if (is_otel_tracing()) {
private$options$otel_session <- otel::start_span(
"callr::r_session",
attributes = otel::as_attributes(options)
)
}
The finalize() method (the finalizer) gets a call to close the span:
if (is_otel_tracing()) {
private$options$otel_session$end()
}
We also add (sub)spans to other operations, e.g. the read() method gets
if (is_otel_tracing()) {
otel::local_session(private$options$otel_session)
spn <- otel::start_local_active_span("callr::r_session$read")
}
To test your instrumentation, you need to install the otelsdk package and you also need a local or remote OpenTelemetry collector.
I suggest you use otel-tui,
a terminal OpenTelemetry viewer. To configure it, use the http exporter,
see Environment Variables:
OTEL_TRACES_EXPORTER=http R -q
By default otel functions never error, to avoid taking down a production app. For development this is not ideal, we want to catch errors early. I suggest you always turn on development mode when instrumenting a package:
OTEL_ENV=dev
OpenTelemetry supports distributed tracing. A span (context) can be serialized, copied to another process, and there it can be used to create child spans.
For applications communicating via HTTP the serialized span context is transmitted in HTTP headers. For our callr example we can copy the context to the R subprocess in environment variables.
For example in the callr:r() code we may write:
if (is_otel_tracing()) {
otel::start_local_active_span(
"callr::r",
attributes = otel::as_attributes(options)
)
hdrs <- otel::pack_http_context()
names(hdrs) <- toupper(names(hdrs))
options$env[names(hdrs)] <- hdrs
}
options$env contains the environment variables callr will set in the
newly started R process. This is where we need to add the output of
pack_http_context(), which contains the serialized representation
of the active span, if there is any.
Additionally, the subprocess needs to pick up the span context from the
environment variables. The callr:::common_hook() internal function
contains the code that the subprocess runs at startup. Here we need to
add:
has_otel <- nzchar(Sys.getenv("TRACEPARENT")) &&
requireNamespace("otel", quietly = TRUE)
assign(envir = env$`__callr_data__`, "has_otel", has_otel)
if (has_otel) {
hdrs <- as.list(c(
traceparent = Sys.getenv("TRACEPARENT"),
tracestate = Sys.getenv("TRACESTATE"),
baggage = Sys.getenv("BAGGAGE")
))
prtctx <- otel::extract_http_context(hdrs)
reg.finalizer(
env$`__callr_data__`,
function(e) e$otel_span$end(),
onexit = TRUE
)
assign(
envir = env$`__callr_data__`,
"otel_span",
otel::start_span(
"callr subprocess",
options = list(parent = prtctx)
)
)
}
First we check if the TRACEPARENT environment variable is set. This
contains the serialization of the parent span. If it exists and the otel
package is also available, then we extract the span context from the
environment variables, and start a new span that is a child span or the
remote span obtained from the environment variables. We also set up a
finalizer that closes this span when the R process terminates.
# See above# See above
Record a value of an OpenTelemetry histogram
histogram_record(name, value, attributes = NULL, context = NULL, meter = NULL)histogram_record(name, value, attributes = NULL, context = NULL, meter = NULL)
name |
Name of the histogram. |
value |
Value to record. |
attributes |
Additional attributes to add. |
context |
Span context. If missing the active context is used, if any. |
meter |
Meter object (otel_meter). Otherwise it is passed to
|
The histogram object (otel_histogram), invisibly.
Other OpenTelemetry metrics instruments:
counter_add(),
gauge_record(),
up_down_counter_add()
Other OpenTelemetry metrics API:
counter_add(),
gauge_record(),
is_measuring_enabled(),
up_down_counter_add()
otel::histogram_record("response-time", 0.2)otel::histogram_record("response-time", 0.2)
This is useful for avoiding computation when logging is inactive.
is_logging_enabled(severity = "info", logger = NULL)is_logging_enabled(severity = "info", logger = NULL)
severity |
Check if logs are emitted at this severity level. |
logger |
Logger object (otel_logger), or a logger name, the
instrumentation scope, to pass to |
It calls get_logger() with name and then it calls the logger's
$is_enabled() method.
TRUE is OpenTelemetry logging is active, FALSE otherwise.
Other OpenTelemetry logs API:
log(),
log_severity_levels
fun <- function() { if (otel::is_logging_enabled()) { xattr <- calculate_some_extra_attributes() otel::log("Starting fun", attributes = xattr) } # ... }fun <- function() { if (otel::is_logging_enabled()) { xattr <- calculate_some_extra_attributes() otel::log("Starting fun", attributes = xattr) } # ... }
This is useful for avoiding computation when metrics collection is inactive.
is_measuring_enabled(meter = NULL)is_measuring_enabled(meter = NULL)
meter |
Meter object (otel_meter), or a meter name, the
instrumentation scope, to pass to |
It calls get_meter() with name and then it calls the meter's
$is_enabled() method.
TRUE is OpenTelemetry metrics collection is active,
FALSE otherwise.
Other OpenTelemetry metrics API:
counter_add(),
gauge_record(),
histogram_record(),
up_down_counter_add()
fun <- function() { if (otel::is_measuring_enabled()) { xattr <- calculate_some_extra_attributes() otel::counter_add("sessions", 1, attributes = xattr) } # ... }fun <- function() { if (otel::is_measuring_enabled()) { xattr <- calculate_some_extra_attributes() otel::counter_add("sessions", 1, attributes = xattr) } # ... }
Checks whether OpenTelemetry tracing is active. This can be useful to avoid unnecessary computation when tracing is inactive.
is_tracing_enabled(tracer = NULL)is_tracing_enabled(tracer = NULL)
tracer |
Tracer object (otel_tracer). It can also be a tracer
name, the instrumentation scope, or |
It calls get_tracer() with name and then it calls the tracer's
$is_enabled() method.
TRUE is OpenTelemetry tracing is active, FALSE otherwise.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
local_active_span(),
start_local_active_span(),
start_span(),
tracing-constants,
with_active_span()
fun <- function() { if (otel::is_tracing_enabled()) { xattr <- calculate_some_extra_attributes() otel::start_local_active_span("fun", attributes = xattr) } # ... }fun <- function() { if (otel::is_tracing_enabled()) { xattr <- calculate_some_extra_attributes() otel::start_local_active_span("fun", attributes = xattr) } # ... }
Activates the span for the caller (or other) frame.
Usually you need this function for spans created with start_span(),
which does not activate the new span. Usually you don't need it for
spans created with start_local_active_span(), because it activates
the new span automatically.
local_active_span(span, end_on_exit = FALSE, activation_scope = parent.frame())local_active_span(span, end_on_exit = FALSE, activation_scope = parent.frame())
span |
The OpenTelemetry span to activate. |
end_on_exit |
Whether to end the span when exiting the activation scope. |
activation_scope |
The scope to activate the span for, defaults to the caller frame. |
When the frame ends, the span is deactivated and the previously active span will be active again, if there was any.
It is possible to activate the same span for multiple R frames.
Nothing.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
is_tracing_enabled(),
start_local_active_span(),
start_span(),
tracing-constants,
with_active_span()
Other tracing for concurrent code:
with_active_span()
fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()
Log an OpenTelemetry log message
log(msg, ..., severity = "info", logger = NULL) log_trace(msg, ..., logger = NULL) log_debug(msg, ..., logger = NULL) log_info(msg, ..., logger = NULL) log_warn(msg, ..., logger = NULL) log_error(msg, ..., logger = NULL) log_fatal(msg, ..., logger = NULL)log(msg, ..., severity = "info", logger = NULL) log_trace(msg, ..., logger = NULL) log_debug(msg, ..., logger = NULL) log_info(msg, ..., logger = NULL) log_warn(msg, ..., logger = NULL) log_error(msg, ..., logger = NULL) log_fatal(msg, ..., logger = NULL)
msg |
Log message. |
... |
Additional arguments are passed to the |
severity |
Log severity, a string, one of "trace", "trace2", "trace3", "trace4", "debug", "debug2", "debug3", "debug4", "info", "info2", "info3", "info4", "warn", "warn2", "warn3", "warn4", "error", "error2", "error3", "error4", "fatal", "fatal2", "fatal3", "fatal4". |
logger |
Logger to use. If not an OpenTelemetry logger object
(otel_logger), then it passed to |
log_trace() is the same as log() with severity_level
"trace".
log_debug() is the same as log() with severity_level
"debug".
log_info() is the same as log() with severity_level
"info".
log_warn() is the same as log() with severity_level
"warn".
log_error) is the same as log() with severity_level
"error".
log_fatal() is the same as log() with severity_level
"fatal".
The logger, invisibly.
Other OpenTelemetry logs API:
is_logging_enabled(),
log_severity_levels
host <- "my.db.host" port <- 6667 otel::log("Connecting to database at {host}:{port}")host <- "my.db.host" port <- 6667 otel::log("Connecting to database at {host}:{port}")
A named integer vector, the severity levels in numeric form. The names are the severity levels in text form. otel functions accept both forms as severity levels, but the text form is more readable.
Not applicable.
Other OpenTelemetry logs API:
is_logging_enabled(),
log()
log_severity_levelslog_severity_levels
This is the meter provider (otel_meter_provider) otel uses when metrics collection is disabled.
All methods are no-ops or return objects that are also no-ops.
Not applicable.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
otel_counter,
otel_gauge,
otel_histogram,
otel_meter,
otel_meter_provider,
otel_up_down_counter
meter_provider_noop$new()meter_provider_noop$new()
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
Usually you do not need to deal with otel_counter objects directly.
counter_add() automatically sets up a meter and creates a counter
instrument, as needed.
A counter object is created by calling the create_counter() method
of an otel_meter_provider().
You can use the add() method to increment the counter by a positive
amount.
In R counters are represented by double values.
Not applicable.
counter$add()Increment the counter by a fixed amount.
counter$add(value, attributes = NULL, span_context = NULL, ...)
value: Value to increment the counter with.
attributes: Additional attributes to add.
span_context: Span context. If missing, the active context is used,
if any.
The counter object itself, invisibly.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_gauge,
otel_histogram,
otel_meter,
otel_meter_provider,
otel_up_down_counter
mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1)mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1)
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
Usually you do not need to deal with otel_gauge objects directly.
gauge_record() automatically sets up a meter and creates a
gauge instrument, as needed.
A gauge object is created by calling the create_gauge() method
of an otel_meter_provider().
You can use the record() method to record the current value.
In R gauge values are represented by doubles.
Not applicable.
gauge$record()Update the statistics with the specified amount.
gauge$record(value, attributes = NULL, span_context = NULL, ...)
value: A numeric value. The current absolute value.
attributes: Additional attributes to add.
span_context: Span context. If missing, the active context is used,
if any.
The gauge object itself, invisibly.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_counter,
otel_histogram,
otel_meter,
otel_meter_provider,
otel_up_down_counter
mp <- get_default_meter_provider() mtr <- mp$get_meter() gge <- mtr$create_gauge("response-time") gge$record(1.123)mp <- get_default_meter_provider() mtr <- mp$get_meter() gge <- mtr$create_gauge("response-time") gge$record(1.123)
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
Usually you do not need to deal with otel_histogram objects directly.
histogram_record() automatically sets up a meter and creates a
histogram instrument, as needed.
A histogram object is created by calling the create_histogram() method
of an otel_meter_provider().
You can use the record() method to update the statistics with the
specified amount.
In R histogram values are represented by doubles.
Not applicable.
histogram$record()Update the statistics with the specified amount.
histogram$record(value, attributes = NULL, span_context = NULL, ...)
value: A numeric value to record.
attributes: Additional attributes to add.
span_context: Span context. If missing, the active context is used,
if any.
The histogram object itself, invisibly.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_meter,
otel_meter_provider,
otel_up_down_counter
mp <- get_default_meter_provider() mtr <- mp$get_meter() hst <- mtr$create_histogram("response-time") hst$record(1.123)mp <- get_default_meter_provider() mtr <- mp$get_meter() hst <- mtr$create_histogram("response-time") hst$record(1.123)
otel_logger_provider -> otel_logger
Usually you do not need to deal with otel_logger objects directly.
log() automatically sets up the logger for emitting the logs.
A logger object is created by calling the get_logger() method of an
otel_logger_provider.
You can use the log() method of the logger object to emit logs.
Typically there is a separate logger object for each instrumented R package.
Not applicable.
logger$is_enabled()Whether the logger is active and emitting logs at a certain severity level.
This is equivalent to the is_logging_enabled() function.
logger$is_enabled(severity = "info", event_id = NULL)
severity: Check if logs are emitted at this severity level.
event_id: Not implemented yet.
Logical scalar.
logger$get_minimum_severity()Get the current minimum severity at which the logger is emitting logs.
logger_get_minimum_severity()
Named integer scalar.
logger$set_minimum_severiry()Set the minimum severity for emitting logs.
logger$set_minimum_severity(minimum_severity)
minimum_severity: Log severity, a string, one of
"trace", "trace2", "trace3", "trace4", "debug", "debug2", "debug3", "debug4", "info", "info2", "info3", "info4", "warn", "warn2", "warn3", "warn4", "error", "error2", "error3", "error4", "fatal", "fatal2", "fatal3", "fatal4".
Nothing.
logger$log()Log an OpenTelemetry log message.
logger$log( msg = "", severity = "info", span_context = NULL, span_id = NULL, trace_id = NULL, trace_flags = NULL, timestamp = SYs.time(), observed_timestamp = NULL, attributes = NULL, .envir = parent.frame() )
msg: Log message, may contain R expressions to evaluate within
braces.
severity: Log severity, a string, one of
"trace", "trace2", "trace3", "trace4", "debug", "debug2", "debug3", "debug4", "info", "info2", "info3", "info4", "warn", "warn2", "warn3", "warn4", "error", "error2", "error3", "error4", "fatal", "fatal2", "fatal3", "fatal4".
span_context: An otel_span_context object to associate the log
message with a span.
span_id: Alternatively to span_context, you can also specify
span_id, trace_id and trace_flags to associate a log message
with a span.
trace_id: Alternatively to span_context, you can also specify
span_id, trace_id and trace_flags to associate a log message
with a span.
trace_flags: Alternatively to span_context, you can also specify
span_id, trace_id and trace_flags to associate a log message
with a span.
timestamp: Time stamp, defaults to the current time. This is the
time the logged event occurred.
observed_timestamp: Observed time stamp, this is the time the
event was observed.
attributes: Optional attributes, see as_attributes() for the
possible values.
The logger object, invisibly.
logger$trace()The same as logger$log(), with severity = "trace".
logger$debug()The same as logger$log(), with severity = "debug".
logger$info()The same as logger$log(), with severity = "info".
logger$warn()The same as logger$log(), with severity = "warn".
logger$error()The same as logger$log(), with severity = "error".
logger$fatal()The same as logger$log(), with severity = "fatal".
Other low level logs API:
get_default_logger_provider(),
get_logger(),
logger_provider_noop,
otel_logger_provider
lp <- get_default_logger_provider() lgr <- lp$get_logger() platform <- utils::sessionInfo()$platform lgr$log("This is a log message from {platform}.", severity = "trace")lp <- get_default_logger_provider() lgr <- lp$get_logger() platform <- utils::sessionInfo()$platform lgr$log("This is a log message from {platform}.", severity = "trace")
otel_logger_provider -> otel_logger
The logger provider defines how logs are exported when collecting telemetry data. It is unlikely that you need to use logger provider objects directly.
Usually there is a single logger provider for an R app or script.
Typically the logger provider is created automatically, at the first
log() call. otel decides which logger provider class to use based on
Environment Variables.
Not applicable.
Note that this list is updated manually and may be incomplete.
logger_provider_noop: No-op logger provider, used when no logs are emitted.
otelsdk::logger_provider_file: Save logs to a JSONL file.
otelsdk::logger_provider_http: Send logs to a collector over HTTP/OTLP.
otelsdk::logger_provider_stdstream: Write logs to standard output or error or to a file. Primarily for debugging.
logger_provider$get_logger()Get or create a new logger object.
logger_provider$get_logger( name = NULL, version = NULL, schema_url = NULL, attributes = NULL )
name Logger name. It makes sense to reuse the tracer name as the
logger name. See get_logger() and default_tracer_name().
version: Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: "1.0.0".
schema_url: Optional. Specifies the Schema URL that should be
recorded in the emitted telemetry.
attributes: Optional. Specifies the instrumentation scope
attributes to associate with emitted telemetry. See as_attributes()
for allowed values. You can also use as_attributes() to convert R
objects to OpenTelemetry attributes.
An OpenTelemetry logger (otel_logger) object.
get_default_logger_provider(), get_logger().
logger_provider$flush()Force any buffered logs to flush. Logger providers might not implement this method.
logger_provider$flush()
Nothing.
Other low level logs API:
get_default_logger_provider(),
get_logger(),
logger_provider_noop,
otel_logger
lp <- otel::get_default_logger_provider() lgr <- lp$get_logger() lgr$is_enabled()lp <- otel::get_default_logger_provider() lgr <- lp$get_logger() lgr$is_enabled()
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
Usually you do not need to deal with otel_meter objects directly.
counter_add(), up_down_counter_add(), histogram_record() and
gauge_record() automatically set up the meter and uses it to create
instruments.
A meter object is created by calling the get_meter() method of an
otel_meter_provider.
You can use the create_counter(), create_up_down_counter(),
create_histogram(), create_gauge() methods of the meter object to
create instruments.
Typically there is a separate meter object for each instrumented R package.
Not applicable.
meter$is_enabled()Whether the meter is active and emitting measurements.
This is equivalent to the is_measuring_enabled() function.
meter$is_enabled()
Logical scalar.
meter$create_counter()Create a new counter instrument.
create_counter(name, description = NULL, unit = NULL)
name: Name of the instrument.
description: Optional description.
unit: Optional measurement unit. If specified, it should use
units from Unified Code for Units of Measure,
according to the OpenTelemetry semantic conventions.
An OpenTelemetry counter (otel_counter) object.
meter$create_up_down_counter()Create a new up-down counter instrument.
create_up_down_counter(name, description = NULL, unit = NULL)
name: Name of the instrument.
description: Optional description.
unit: Optional measurement unit. If specified, it should use
units from Unified Code for Units of Measure,
according to the OpenTelemetry semantic conventions.
An OpenTelemetry counter (otel_up_down_counter) object.
meter$create_histogram()Create a new histogram.
create_histogram(name, description = NULL, unit = NULL)
name: Name of the instrument.
description: Optional description.
unit: Optional measurement unit. If specified, it should use
units from Unified Code for Units of Measure,
according to the OpenTelemetry semantic conventions.
An OpenTelemetry histogram (otel_histogram) object.
meter$create_gauge()Create a new gauge.
create_gauge(name, description = NULL, unit = NULL)
name: Name of the instrument.
description: Optional description.
unit: Optional measurement unit. If specified, it should use
units from Unified Code for Units of Measure,
according to the OpenTelemetry semantic conventions.
An OpenTelemetry gauge (otel_gauge) object.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_histogram,
otel_meter_provider,
otel_up_down_counter
mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1)mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1)
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
The meter provider defines how metrics are exported when collecting telemetry data. It is unlikely that you need to use meter provider objects directly.
Usually there is a single meter provider for an R app or script.
Typically the meter provider is created automatically, at the first
counter_add(), up_down_counter_add(), histogram_record(),
gauge_record() or get_meter() call. otel decides which meter
provider class to use based on Environment Variables.
Not applicable.
Note that this list is updated manually and may be incomplete.
meter_provider_noop: No-op meter provider, used when no metrics are emitted.
otelsdk::meter_provider_file: Save metrics to a JSONL file.
otelsdk::meter_provider_http: Send metrics to a collector over HTTP/OTLP.
otelsdk::meter_provider_memory: Collect emitted metrics in memory. For testing.
otelsdk::meter_provider_stdstream: Write metrics to standard output or error or to a file. Primarily for debugging.
meter_provider$get_meter()Get or create a new meter object.
meter_provider$get_meter( name = NULL, version = NULL, schema_url = NULL, attributes = NULL )
name: Meter name, see get_meter().
version: Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: "1.0.0".
schema_url: Optional. Specifies the Schema URL that should be
recorded in the emitted telemetry.
attributes: Optional. Specifies the instrumentation scope
attributes to associate with emitted telemetry. See as_attributes()
for allowed values. You can also use as_attributes() to convert R
objects to OpenTelemetry attributes.
Returns an OpenTelemetry meter (otel_meter) object.
get_default_meter_provider(), get_meter().
meter_provider$flush()Force any buffered metrics to flush. Meter providers might not implement this method.
meter_provider$flush()
Nothing.
meter_provider$shutdown()Stop the meter provider. Stops collecting and emitting measurements.
meter_provider$shurdown()
Nothing
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_histogram,
otel_meter,
otel_up_down_counter
mp <- otel::get_default_meter_provider() mtr <- mp$get_meter() mtr$is_enabled()mp <- otel::get_default_meter_provider() mtr <- mp$get_meter() mtr$is_enabled()
otel_tracer_provider -> otel_tracer -> otel_span -> otel_span_context
An otel_span object represents an OpenTelemetry span.
Use start_local_active_span() or start_span() to create and start
a span.
Call end_span() to end a span explicitly. (See
start_local_active_span() and local_active_span() to end a span
automatically.)
Not applicable.
The span starts when it is created in the start_local_active_span()
or start_span() call.
The span ends when end_span() is called on it, explicitly or
automatically via start_local_active_span() or local_active_span().
After a span is created it may be active or inactively, independently of its lifetime. A live span (i.e. a span that hasn't ended yet) may be inactive. While this is less common, a span that has ended may still be active.
When otel creates a new span, it sets the parent span of the new span to the active span by default.
start_local_active_span() creates a new span, starts it and activates
it for the caller frame. It also automatically ends the span when the
caller frame exits.
start_span() creates a new span and starts it, but it does not
activate it. You must activate the span manually using
local_active_span() or with_active_span(). You must also end the
span manually with an end_span() call. (Or the end_on_exit argument
of local_active_span() or with_active_span().)
OpenTelemetry spans form a hierarchy: a span can refer to a parent span. A span without a parent span is called a root span. A trace is a set of connected spans.
When otel creates a new span, it sets the parent span of the new span to the active span by default.
Alternatively, you can set the parent span of the new span manually.
You can also make the new span be a root span, by setting parent = NA
in options to the start_local_active_span() or start_span() call.
span$add_event()Add a single event to the span.
span$add_event(name, attributes = NULL, timestamp = NULL)
name: Event name.
attributes: Attributes to add to the event. See as_attributes()
for supported R types. You may also use as_attributes() to convert
an R object to an OpenTelemetry attribute value.
timestamp: A base::POSIXct object. If missing, the current time is
used.
The span object itself, invisibly.
span$end()End the span. Calling this method is equivalent to calling the
end_span() function on the span.
Spans created with start_local_active_span() end automatically by
default. You must end every other span manually, by calling end_span,
or using the end_on_exit argument of local_active_span() or
with_active_span().
Calling the span$end() method (or end_span()) on a span multiple
times is not an error, the first call ends the span, subsequent calls do
nothing.
span$end(options = NULL, status_code = NULL)
options: Named list of options. Possible entry:
end_steady_time: A base::POSIXct object that will be used as
a steady timer.
status_code: Span status code to set before ending the span, see
the span$set_status() method for possible values.
The span object itself, invisibly.
span$get_context()Get a span's span context. The span context is an otel_span_context object that can be serialized, copied to other processes, and it can be used to create new child spans.
span$get_context()
An otel_span_context object.
span$is_recording()Checks whether a span is recorded. If tracing is off, or the span ended already, or the sampler decided not to record the trace the span belongs to.
span$is_recording()
A logical scalar, TRUE if the span is recorded.
span$record_exception()Record an exception (error, usually) event for a span.
If the span was created with start_local_active_span(), or it was
ended automatically with local_active_span() or with_active_span(),
then otel records exceptions automatically, and you don't need to call
this function manually.
You can still use it to record exceptions that are not R errors.
span$record_exception(error_condition, attributes, ...)
error_condition: An R error object to record.
attributes: Additional attributes to add to the exception event.
...: Passed to the span$add_event() method.
The span object itself, invisibly.
span$set_attribute()Set a single attribute. It is better to set attributes at span creation, instead of calling this method later, since samplers can only make decisions based on attributes present at span creation.
span$set_attribute(name, value)
name: Attribute name.
value: Attribute value. See as_attributes() for supported R types.
You may also use as_attributes() to convert an R object to an
OpenTelemetry attribute value.
The span object itself, invisibly.
span$set_status()Set the status of the span.
If the span was created with start_local_active_span(), or it was
ended automatically with local_active_span() or with_active_span(),
then otel sets the status of the span automatically to ok or error,
depending on whether an error happened in the frame the span was
activated for.
Otherwise the default span status is unset, and you need to set it
manually.
span$set_status(status_code, description = NULL)
status_code: Possible values:
unset, ok, error.
description: Optional description, a string.
The span itself, invisibly.
span$update_name()Update the span's name. Overrides the name give in
start_local_active_span() or start_span().
It is undefined whether a sampler will use the original or the new name.
span$update_name(name)
name: String, the new span name.
The span object itself, invisibly.
Other low level trace API:
get_default_tracer_provider(),
get_tracer(),
otel_span_context,
otel_tracer,
otel_tracer_provider,
tracer_provider_noop
fn <- function() { trc <- otel::get_tracer("myapp") spn <- trc$start_span("fn") # ... spn$set_attribute("key", "value") # ... on.exit(spn$end(status_code = "error"), add = TRUE) # ... spn$end(status_code = "ok") } fn()fn <- function() { trc <- otel::get_tracer("myapp") spn <- trc$start_span("fn") # ... spn$set_attribute("key", "value") # ... on.exit(spn$end(status_code = "error"), add = TRUE) # ... spn$end(status_code = "ok") } fn()
otel_tracer_provider -> otel_tracer -> otel_span -> otel_span_context
This is a representation of a span that can be serialized, copied to other processes, and it can be used to create new child spans.
Not applicable.
span_context$get_span_id()Get the id of the span.
span_context$get_span_id()
String scalar, a span id. For invalid spans it is invalid_span_id.
span_context$get_trace_flags()Get the trace flags of a span.
See the specification for more details on trace flags.
span_context$get_trace_flags()
A list with entries:
is_sampled: logical flag, whether the trace of the span is sampled.
If FALSE then the caller is not recording the trace. See details in
the specification.
is_random: logical flag, it specifies how trace ids are generated.
See details in the specification.
span_context$get_trace_id()Get the id of the trace the span belongs to.
span_context$get_trace_id()
A string scalar, a trace id. For invalid spans it is invalid_trace_id.
span_context$is_remote()Whether the span was propagated from a remote parent.
span_context$is_remote()
A logical scalar.
span_context$is_sampled()Whether the span is sampled. This is the same as the is_sampled
trace flags, see get_trace_flags() above.
span_context$is_sampled()
Logical scalar.
span_context$is_valid()Whether the span is valid. Sometimes otel functions return an
invalid span or a span context referring to an invalid span. E.g.
get_active_span_context() does that if there is no active span.
is_valid() checks if the span is valid.
An span id of an invalid span is invalid_span_id.
span_context$is_valid()
A logical scalar.
span_context$to_http_headers()Serialize the span context into one or more HTTP headers that can be transmitted to other processes or servers, to create a distributed trace.
The other process can deserialize these headers into a span context that can be used to create new remote spans.
span_context$to_http_headers()
A named character vector, the HTTP header representation of the span
context. Usually includes a traceparent header. May include other
headers.
Other low level trace API:
get_default_tracer_provider(),
get_tracer(),
otel_span,
otel_tracer,
otel_tracer_provider,
tracer_provider_noop
spc <- get_active_span_context() spc$get_trace_flags() spc$get_trace_id() spc$get_span_id() spc$is_remote() spc$is_sampled() spc$is_valid() spc$to_http_headers()spc <- get_active_span_context() spc$get_trace_flags() spc$get_trace_id() spc$get_span_id() spc$is_remote() spc$is_sampled() spc$is_valid() spc$to_http_headers()
otel_tracer_provider -> otel_tracer -> otel_span -> otel_span_context
Usually you do not need to deal with otel_tracer objects directly.
start_local_active_span() (and start_span()) automatically
sets up the tracer and uses it to create spans.
A tracer object is created by calling the get_tracer() method of an
otel_tracer_provider.
You can use the start_span() method of the tracer object to create a
span.
Typically there is a separate tracer object for each instrumented R package.
Not applicable.
tracer$start_span()Creates and starts a new span.
It does not activate the new span.
It is equivalent to the start_span() function.
tracer_start_span( name = NULL, attributes = NULL, links = NULL, options = NULL )
name: Name of the span. If not specified it will be "<NA>".
attributes: Span attributes. OpenTelemetry supports the following
R types as attributes: 'character, logical, double, integer.
You may use as_attributes() to convert other R types to
OpenTelemetry attributes.
links: A named list of links to other spans. Every link must be an
OpenTelemetry span (otel_span) object, or a list with a span
object as the first element and named span attributes as the rest.
options: A named list of span options. May include:
start_system_time: Start time in system time.
start_steady_time: Start time using a steady clock.
parent: A parent span or span context. If it is NA, then the
span has no parent and it will be a root span. If it is NULL, then
the current context is used, i.e. the active span, if any.
kind: Span kind, one of span_kinds:
"internal", "server", "client", "producer", "consumer".
A new otel_span object.
tracer$is_enabled()Whether the tracer is active and recording traces.
This is equivalent to the is_tracing_enabled() function.
tracer$is_enabled()
Logical scalar.
tracer$flush()Flush the tracer provider: force any buffered spans to flush. Tracer providers might not implement this method.
tracer$flush()
Nothing.
Other low level trace API:
get_default_tracer_provider(),
get_tracer(),
otel_span,
otel_span_context,
otel_tracer_provider,
tracer_provider_noop
tp <- get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled()tp <- get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled()
otel_tracer_provider -> otel_tracer -> otel_span -> otel_span_context
The tracer provider defines how traces are exported when collecting telemetry data. It is unlikely that you'd need to use tracer provider objects directly.
Usually there is a single tracer provider for an R app or script.
Typically the tracer provider is created automatically, at the first
start_local_active_span() or start_span() call. otel decides which
tracer provider class to use based on Environment Variables.
Not applicable.
Note that this list is updated manually and may be incomplete.
tracer_provider_noop: No-op tracer provider, used when no traces are emitted.
otelsdk::tracer_provider_file: Save traces to a JSONL file.
otelsdk::tracer_provider_http: Send traces to a collector over HTTP/OTLP.
otelsdk::tracer_provider_memory: Collect emitted traces in memory. For testing.
otelsdk::tracer_provider_stdstream: Write traces to standard output or error or to a file. Primarily for debugging.
tracer_provider$get_tracer()Get or create a new tracer object.
tracer_provider$get_tracer( name = NULL, version = NULL, schema_url = NULL, attributes = NULL )
name: Tracer name, see get_tracer().
version: Optional. Specifies the version of the instrumentation
scope if the scope has a version (e.g. R package version).
Example value: "1.0.0".
schema_url: Optional. Specifies the Schema URL that should be
recorded in the emitted telemetry.
attributes: Optional. Specifies the instrumentation scope
attributes to associate with emitted telemetry. See as_attributes()
for allowed values. You can also use as_attributes() to convert R
objects to OpenTelemetry attributes.
Returns an OpenTelemetry tracer (otel_tracer) object.
get_default_tracer_provider(), get_tracer().
tracer_provider$flush()Force any buffered spans to flush. Tracer providers might not implement this method.
tracer_provider$flush()
Nothing.
Other low level trace API:
get_default_tracer_provider(),
get_tracer(),
otel_span,
otel_span_context,
otel_tracer,
tracer_provider_noop
tp <- otel::get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled()tp <- otel::get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled()
otel_meter_provider -> otel_meter -> otel_counter, otel_up_down_counter, otel_histogram, otel_gauge
Usually you do not need to deal with otel_up_down_counter objects directly.
up_down_counter_add() automatically sets up a meter and creates an
up-down counter instrument, as needed.
An up-down counter object is created by calling the
create_up_down_counter() method of an otel_meter_provider().
You can use the add() method to increment or decrement the counter.
In R up-down counters are represented by double values.
Not applicable.
up_down_counter$add()Increment or decrement the up-down counter by a fixed amount.
up_down_counter$add(value, attributes = NULL, span_context = NULL, ...)
value: Value to increment of decrement the up-down counter with.
attributes: Additional attributes to add.
span_context: Span context. If missing, the active context is used,
if any.
The up-down counter object itself, invisibly.
Other low level metrics API:
get_default_meter_provider(),
get_meter(),
meter_provider_noop,
otel_counter,
otel_gauge,
otel_histogram,
otel_meter,
otel_meter_provider
mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_up_down_counter("session") ctr$add(1)mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_up_down_counter("session") ctr$add(1)
The returned headers can be sent over HTTP, or set as environment variables for subprocesses.
pack_http_context()pack_http_context()
A named character vector, with lowercase names. It might be an empty vector, e.g. if tracing is disabled.
hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid()hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid()
Creates, starts and activates an OpenTelemetry span.
Usually you want this functions instead of start_span(), which does
not activate the new span.
start_local_active_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL, activation_scope = parent.frame(), end_on_exit = TRUE )start_local_active_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL, activation_scope = parent.frame(), end_on_exit = TRUE )
name |
Name of the span. If not specified it will be |
attributes |
Span attributes. OpenTelemetry supports the following
R types as attributes: 'character, logical, double, integer.
You may use |
links |
A named list of links to other spans. Every link must be an OpenTelemetry span (otel_span) object, or a list with a span object as the first element and named span attributes as the rest. |
options |
A named list of span options. May include:
|
... |
Additional arguments are passed to the |
tracer |
A tracer object or the name of the tracer to use, see
|
activation_scope |
The R scope to activate the span for. Defaults to the caller frame. |
end_on_exit |
Whether to also end the span when the activation scope exits. |
If end_on_exit is TRUE (the default), then it also ends the span
when the activation scope finishes.
The new OpenTelemetry span object (of class otel_span), invisibly. See otel_span for information about the returned object.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
is_tracing_enabled(),
local_active_span(),
start_span(),
tracing-constants,
with_active_span()
fn1 <- function() { otel::start_local_active_span("fn1") fn2() } fn2 <- function() { otel::start_local_active_span("fn2") } fn1()fn1 <- function() { otel::start_local_active_span("fn1") fn2() } fn2 <- function() { otel::start_local_active_span("fn2") } fn1()
Creates a new OpenTelemetry span and starts it, without activating it.
Usually you want start_local_active_span() instead of start_span.
start_local_active_span() also activates the span for the caller frame,
and ends the span when the caller frame exits.
start_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL )start_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL )
name |
Name of the span. If not specified it will be |
attributes |
Span attributes. OpenTelemetry supports the following
R types as attributes: 'character, logical, double, integer.
You may use |
links |
A named list of links to other spans. Every link must be an OpenTelemetry span (otel_span) object, or a list with a span object as the first element and named span attributes as the rest. |
options |
A named list of span options. May include:
|
... |
Additional arguments are passed to the |
tracer |
A tracer object or the name of the tracer to use, see
|
Only use start_span() is you need to manage the span's activation
manually. Otherwise use start_local_active_span().
You must end the span by calling end_span(). Alternatively you
can also end it with local_active_span() or with_active_span() by
setting end_on_exit = TRUE.
It is a good idea to end spans created with start_span() in an
base::on.exit() call.
An OpenTelemetry span (otel_span).
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
is_tracing_enabled(),
local_active_span(),
start_local_active_span(),
tracing-constants,
with_active_span()
fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn2 <- otel::start_local_active_span("myfun/2") } myfun2 <- function() { # activate span for this function otel::local_active_span(spn) # create child span spn3 <- otel::start_local_active_span("myfun/3") } myfun() myfun2() end_span(spn) } fun()
This is the tracer provider (otel_tracer_provider) otel uses when tracing is disabled.
All methods are no-ops or return objects that are also no-ops.
Not applicable.
Other low level trace API:
get_default_tracer_provider(),
get_tracer(),
otel_span,
otel_span_context,
otel_tracer,
otel_tracer_provider
tracer_provider_noop$new()tracer_provider_noop$new()
Various constants related OpenTelemetry tracing.
invalid_trace_id invalid_span_id span_kinds span_status_codesinvalid_trace_id invalid_span_id span_kinds span_status_codes
invalid_trace_idinvalid_trace_id is a string scalar, an invalid trace id. If there is
no active span, then get_active_span_context() returns a span context
that has an invalid trace id.
invalid_span_idinvalid_span_id is a string scalar, an invalid span id. If there is
no active span, then get_active_span_context() returns a span context
that has an invalid span id.
span_kindsspan_kinds is a character vector listing all possible span kinds.
See the OpenTelemetry specification for
when to use which.
span_status_codesspan_status_codes is a character vector listing all possible span
status codes. You can set the status code of a a span with the
set_status() method of otel_span objects. If not set explicitly,
and the span is ended automatically (by start_local_active_span(),
local_active_span() or with_active_span()), then otel sets the
status automatically to "ok" or "error", depending on whether the span
ended during handling an error.
Not applicable.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
is_tracing_enabled(),
local_active_span(),
start_local_active_span(),
start_span(),
with_active_span()
invalid_trace_id invalid_span_id span_kinds span_status_codesinvalid_trace_id invalid_span_id span_kinds span_status_codes
Increase or decrease an OpenTelemetry up-down counter
up_down_counter_add( name, value = 1L, attributes = NULL, context = NULL, meter = NULL )up_down_counter_add( name, value = 1L, attributes = NULL, context = NULL, meter = NULL )
name |
Name of the up-down counter. |
value |
Value to add to or subtract from the counter, defaults to 1. |
attributes |
Additional attributes to add. |
context |
Span context. If missing the active context is used, if any. |
meter |
Meter object (otel_meter). Otherwise it is passed to
|
The up-down counter object (otel_up_down_counter), invisibly.
Other OpenTelemetry metrics instruments:
counter_add(),
gauge_record(),
histogram_record()
Other OpenTelemetry metrics API:
counter_add(),
gauge_record(),
histogram_record(),
is_measuring_enabled()
otel::up_down_counter_add("session-count", 1)otel::up_down_counter_add("session-count", 1)
Activates the span for evaluating an R expression.
Usually you need this function for spans created with start_span(),
which does not activate the new span. Usually you don't need it for
spans created with start_local_active_span(), because it activates
the new span automatically.
with_active_span(span, expr, end_on_exit = FALSE)with_active_span(span, expr, end_on_exit = FALSE)
span |
The OpenTelemetry span to activate. |
expr |
R expression to evaluate. |
end_on_exit |
Whether to end after evaluating the R expression. |
After expr is evaluated (or an error occurs), the span is deactivated
and the previously active span will be active again, if there was any.
It is possible to activate the same span for multiple R frames.
The return value of expr.
Other OpenTelemetry trace API:
Zero Code Instrumentation,
end_span(),
is_tracing_enabled(),
local_active_span(),
start_local_active_span(),
start_span(),
tracing-constants
Other tracing for concurrent code:
local_active_span()
fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { otel::with_active_span(spn, { # create child span spn2 <- otel::start_local_active_span("myfun/2") }) } myfun2 <- function() { otel::with_active_span(spn, { # create child span spn3 <- otel::start_local_active_span("myfun/3") }) } myfun() myfun2() end_span(spn) } fun()fun <- function() { # start span, do not activate spn <- otel::start_span("myfun") # do not leak resources on.exit(otel::end_span(spn), add = TRUE) myfun <- function() { otel::with_active_span(spn, { # create child span spn2 <- otel::start_local_active_span("myfun/2") }) } myfun2 <- function() { otel::with_active_span(spn, { # create child span spn3 <- otel::start_local_active_span("myfun/3") }) } myfun() myfun2() end_span(spn) } fun()
otel supports zero-code instrumentation (ZCI) via the
OTEL_INSTRUMENT_R_PKGS environment variable. Set this to a comma
separated list of package names, the packages that you want to
instrument. Then otel will hook up base::trace() to produce
OpenTelemetry output from every function of these packages.
By default all functions of the listed packages are instrumented. To
instrument a subset of all functions set the
OTEL_INSTRUMENT_R_PKGS_<PKG>_INCLUDE environment variable to a list of
glob expressions. <PKG> is the package name in all capital letters.
Only functions that match to at least one glob expression will be
instrumented.
To exclude functions from instrumentation, set the
OTEL_INSTRUMENT_R_PKGS_<PKG>_EXCLUDE environment variable to a list of
glob expressions. <PKG> is the package name in all capital letters.
Functions that match to at least one glob expression will not be
instrumented. Inclusion globs are applied before exclusion globs.
If the user calls base::trace() on an instrumented function, that
deletes the instrumentation, since the second base::trace() call
overwrites the first.
Not applicable.
Other OpenTelemetry trace API:
end_span(),
is_tracing_enabled(),
local_active_span(),
start_local_active_span(),
start_span(),
tracing-constants,
with_active_span()
# To run an R script with ZCI: # OTEL_TRACES_EXPORTER=http OTEL_INSTRUMENT_R_PKGS=dplyr,tidyr R -q -f script.R# To run an R script with ZCI: # OTEL_TRACES_EXPORTER=http OTEL_INSTRUMENT_R_PKGS=dplyr,tidyr R -q -f script.R