otel/0000755000176200001440000000000015054325537011226 5ustar liggesusersotel/tests/0000755000176200001440000000000015046400571012361 5ustar liggesusersotel/tests/testthat/0000755000176200001440000000000015054325537014230 5ustar liggesusersotel/tests/testthat/test-utils.R0000644000176200001440000000327315040770460016467 0ustar liggesuserstest_that("%||%", { expect_equal(NULL %||% "foo", "foo") expect_equal(NULL %||% NULL, NULL) expect_equal("foo" %||% stop("no!"), "foo") }) test_that("errmsg", { expect_snapshot(errmsg("this is a ", "message instead of an error")) }) test_that("msg", { loadNamespace("cli") expect_snapshot(msg("just being busy")) fake(msg, "loadedNamespaces", character()) expect_snapshot(msg("nothing to see here")) }) test_that("get_env", { withr::local_envvar( THIS_IS_SET = "foo", THIS_IS_NOT = NA_character_ ) expect_equal(get_env("THIS_IS_SET"), "foo") expect_null(get_env("THIS_IS_NOT")) }) test_that("glob_filter", { fns <- c( "default_logs_exporter_envvar", "default_logs_exporter_envvar_r", "errmsg", "friendly_type", "gauge", "get_default_logger_provider", "get_default_logger_provider_dev" ) expect_equal(glob_filter(fns), fns) expect_snapshot({ glob_filter(fns, include = "default_*") glob_filter(fns, include = c("default_*", "?auge")) glob_filter(fns, exclude = c("errmsg", "get_*")) glob_filter(fns, include = c("default_*", "?auge"), exclude = "*_r") }) }) test_that("get_env_count", { withr::local_envvar(FOO = 10) expect_equal(get_env_count("FOO", stop("no")), 10L) withr::local_envvar(FOO = "inf") expect_equal(get_env_count("FOO", stop("no")), Inf) withr::local_envvar(FOO = "bad") expect_equal(get_env_count("FOO", 1L), 1L) expect_equal(get_env_count("FOO", "1"), 1L) withr::local_envvar(FOO = "-100") expect_equal(get_env_count("FOO", 1L), 1L) expect_equal(get_env_count("FOO", "1"), 1L) expect_snapshot(error = TRUE, { get_env_count("FOO", -1L) get_env_count("FOO", "bad-default") }) }) otel/tests/testthat/test-print.R0000644000176200001440000000314015040773107016455 0ustar liggesuserstest_that("format.otel_tracer_privider", { local_otel_off() expect_snapshot(get_default_tracer_provider()) }) test_that("format.otel_tracer", { local_otel_off() expect_snapshot(get_default_tracer_provider()$get_tracer()) }) test_that("format.otel_span", { local_otel_off() trc <- get_default_tracer_provider()$get_tracer() expect_snapshot(trc$start_span()) }) test_that("format.otel_span_context", { local_otel_off() trc <- get_default_tracer_provider()$get_tracer() expect_snapshot(trc$start_span()$get_context()) }) test_that("format.otel_logger_provider", { local_otel_off() expect_snapshot(get_default_logger_provider()) }) test_that("format.otel_logger", { local_otel_off() expect_snapshot(get_default_logger_provider()$get_logger()) }) test_that("format.otel_meter_provider", { local_otel_off() expect_snapshot(get_default_meter_provider()) }) test_that("format.otel_meter", { local_otel_off() expect_snapshot(get_default_meter_provider()$get_meter()) }) test_that("format.otel_counter", { local_otel_off() mtr <- get_default_meter_provider()$get_meter() expect_snapshot(mtr$create_counter("ctr")) }) test_that("format.otel_up_down_counter", { local_otel_off() mtr <- get_default_meter_provider()$get_meter() expect_snapshot(mtr$create_up_down_counter("ctr")) }) test_that("format.otel_histogram", { local_otel_off() mtr <- get_default_meter_provider()$get_meter() expect_snapshot(mtr$create_histogram("hst")) }) test_that("format.otel_gauge", { local_otel_off() mtr <- get_default_meter_provider()$get_meter() expect_snapshot(mtr$create_gauge("gge")) }) otel/tests/testthat/test-onload.R0000644000176200001440000000577415037460144016614 0ustar liggesuserstest_that("safe functions are used in prod", { expect_equal(the$mode, "prod") expect_equal( get_default_tracer_provider, get_default_tracer_provider_safe ) expect_equal(get_tracer, get_tracer_safe) }) test_that("otel_save_cache, otel_restore_cache", { on.exit(otel_clean_cache(), add = TRUE) otel_clean_cache() the[["tracer_provider"]] <- "bar" the[["meter_provider"]] <- 1:10 the[["mode"]] <- "prod" env <- otel_save_cache() expect_true(is.environment(env)) expect_snapshot(as.list(env)) otel_clean_cache() otel_restore_cache(env) expect_true(is.environment(the)) expect_snapshot(as.list(the)) }) test_that("setup_dev_env", { check_prod <- function(env) { expect_null(env$get_default_tracer_provider) expect_null(env$get_default_logger_provider) expect_null(env$get_default_meter_provider) expect_null(env$start_shiny_app) expect_null(env$start_shiny_session) expect_null(env$start_span) } check_dev <- function(env) { expect_equal( env$get_default_tracer_provider, get_default_tracer_provider_dev ) expect_equal( env$get_default_logger_provider, get_default_logger_provider_dev ) expect_equal( env$get_default_meter_provider, get_default_meter_provider_dev ) } withr::local_envvar(OTEL_ENV = NA_character_) fake <- new.env(parent = emptyenv()) setup_dev_env(fake) check_prod(fake) withr::local_envvar(OTEL_ENV = "prod") fake <- new.env(parent = emptyenv()) setup_dev_env(fake) check_prod(fake) withr::local_envvar(OTEL_ENV = "dev") fake <- new.env(parent = emptyenv()) setup_dev_env(fake) check_dev(fake) }) test_that("setup_r_trace", { # env var not set fake(setup_r_trace, "get_tracer", function(...) stop("no")) withr::local_envvar(OTEL_R_INSTRUMENT_PKGS = NA_character_) expect_silent(setup_r_trace()) # tracer not enabled fake( setup_r_trace, "get_tracer", function(...) list(is_enabled = function() FALSE) ) fake( setup_r_trace, "trace_namespace", function(...) stop("nono") ) withr::local_envvar(OTEL_R_INSTRUMENT_PKGS = "foobar") expect_silent(setup_r_trace()) # tracer enabled, package already loaded fake( setup_r_trace, "get_tracer", function(...) list(is_enabled = function() TRUE) ) fake(setup_r_trace, "loadedNamespaces", "ok") fake(setup_r_trace, "trace_namespace", function(...) res <<- list(...)) fake(setup_r_trace, "setHook", function(...) stop("not yet")) withr::local_envvar(OTEL_R_INSTRUMENT_PKGS = "ok") res <- NULL setup_r_trace() expect_snapshot(res) # inclusions, exclusions withr::local_envvar( OTEL_R_INSTRUMENT_PKGS_OK_INCLUDE = "inc*", OTEL_R_INSTRUMENT_PKGS_OK_EXCLUDE = "exclude.*" ) res <- NULL setup_r_trace() expect_snapshot(res) # not loaded, set hook fake(setup_r_trace, "loadedNamespaces", "nothere") fake(setup_r_trace, "setHook", function(...) res <<- list(...)) res <- NULL setup_r_trace() expect_snapshot({ res[[1]] body(res[[2]]) }) }) otel/tests/testthat/test-spelling.R0000644000176200001440000000041315033144176017136 0ustar liggesuserstest_that("spelling", { skip_on_cran() skip_on_covr() pkg <- test_path("../../") if (!file.exists(file.path(pkg, "DESCRIPTION"))) { pkg <- file.path(pkg, "00_pkg_src", .packageName) } expect_snapshot({ spelling::spell_check_package(pkg) }) }) otel/tests/testthat/fixtures/0000755000176200001440000000000015044612736016100 5ustar liggesusersotel/tests/testthat/fixtures/oteltest/0000755000176200001440000000000015044614345017741 5ustar liggesusersotel/tests/testthat/fixtures/oteltest/R/0000755000176200001440000000000015044613533020140 5ustar liggesusersotel/tests/testthat/fixtures/oteltest/R/oteltest.R0000644000176200001440000000115215044615643022131 0ustar liggesusers#' @export runme <- function() { message("runme in") child1() object[["notthis"]]() child2() message("runme out") } child1 <- function() { message(" child1 in") grandchild1() grandchild2() message(" child1 out") } child2 <- function() { message(" child2 in") grandchild1() grandchild2() message(" child2 out") } grandchild1 <- function() { message(" grandchild1") } grandchild2 <- function() { message(" grandchild2") } object <- list( 1, 2, 3, notthis = function() { # this won't be instrumented, not a top-level package object message(" notthis") } ) otel/tests/testthat/fixtures/oteltest/NAMESPACE0000644000176200001440000000007415044614534021161 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(runme) otel/tests/testthat/fixtures/oteltest/inst/0000755000176200001440000000000015044614356020720 5ustar liggesusersotel/tests/testthat/fixtures/oteltest/inst/runme.R0000644000176200001440000000015115044617625022170 0ustar liggesusers# need to load load, otherwise ZCI cannot work loadNamespace("otel") library(oteltest) oteltest::runme() otel/tests/testthat/fixtures/oteltest/DESCRIPTION0000644000176200001440000000060515044612737021453 0ustar liggesusersPackage: oteltest Title: What the Package Does (One Line, Title Case) Version: 0.0.0.9000 Authors@R: person("First", "Last", , "first.last@example.com", role = c("aut", "cre")) Description: What the package does (one paragraph). License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a license Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2.9000 otel/tests/testthat/test-tracer-name.R0000644000176200001440000001012615040772117017521 0ustar liggesuserstest_that("default_tracer_name", { skip_on_cran() withr::local_envvar(structure( NA_character_, names = otel_emit_scopes_envvar )) withr::local_envvar(structure( NA_character_, names = otel_suppress_scopes_envvar )) expect_equal( default_tracer_name("me-me-me"), list(name = "me-me-me", package = NA_character_, on = TRUE) ) r <- list(name = "org.r-project.R", package = "R", on = TRUE) # otel is ignored fake(default_tracer_name, "topenv", asNamespace("otel")) expect_equal(default_tracer_name(), r) # otelsdk is ignored fake(default_tracer_name, "topenv", asNamespace("otelsdk")) expect_equal(default_tracer_name(), r) # base env -> R fake(default_tracer_name, "topenv", baseenv()) expect_equal(default_tracer_name(), r) # global env -> R fake(default_tracer_name, "topenv", globalenv()) expect_equal(default_tracer_name(), r) # package with 'otel_tracer_name' fake(default_tracer_name, "topenv", asNamespace("testthat")) fake(default_tracer_name, "get0", "custom-name") expect_equal( default_tracer_name(), list(name = "custom-name", package = "testthat", on = TRUE) ) # pakage without 'otel_tracer_name' fake(default_tracer_name, "topenv", asNamespace("testthat")) fake(default_tracer_name, "get0", NULL) expect_equal( default_tracer_name(), list(name = "r.package.testthat", package = "testthat", on = TRUE) ) }) test_that("is_scope_on", { withr::local_envvar(structure( NA_character_, names = otel_emit_scopes_envvar )) withr::local_envvar(structure( NA_character_, names = otel_suppress_scopes_envvar )) expect_true(is_scope_on(list(name = "foo", package = "bar"))) # only the ones that are explicitly included withr::local_envvar(structure("foo", names = otel_emit_scopes_envvar)) expect_true(is_scope_on(list(name = "foo"))) expect_true(is_scope_on(list(package = "foo"))) expect_false(is_scope_on(list(name = "fooo"))) expect_false(is_scope_on(list(name = "fo"))) expect_false(is_scope_on(list(package = "fooo"))) expect_false(is_scope_on(list(package = "fo"))) withr::local_envvar(structure("foo,bar", names = otel_emit_scopes_envvar)) expect_true(is_scope_on(list(name = "foo"))) expect_true(is_scope_on(list(package = "foo"))) expect_true(is_scope_on(list(name = "bar"))) expect_true(is_scope_on(list(package = "bar"))) expect_false(is_scope_on(list(name = "fooo"))) expect_false(is_scope_on(list(name = "fo"))) expect_false(is_scope_on(list(package = "fooo"))) expect_false(is_scope_on(list(package = "fo"))) withr::local_envvar(structure("foo*,ba?", names = otel_emit_scopes_envvar)) expect_true(is_scope_on(list(name = "foo"))) expect_true(is_scope_on(list(package = "foo"))) expect_true(is_scope_on(list(name = "bar"))) expect_true(is_scope_on(list(package = "bar"))) expect_true(is_scope_on(list(name = "baz"))) expect_true(is_scope_on(list(package = "baz"))) expect_true(is_scope_on(list(name = "fooo"))) expect_false(is_scope_on(list(name = "fo"))) expect_true(is_scope_on(list(package = "fooo"))) expect_false(is_scope_on(list(package = "fo"))) expect_false(is_scope_on(list(package = "barz"))) # exclude some withr::local_envvar(structure( NA_character_, names = otel_emit_scopes_envvar )) withr::local_envvar(structure("bar", names = otel_suppress_scopes_envvar)) expect_true(is_scope_on(list(name = "foo"))) expect_true(is_scope_on(list(package = "foo"))) expect_false(is_scope_on(list(name = "bar"))) expect_false(is_scope_on(list(package = "bar"))) expect_true(is_scope_on(list(name = "fooo"))) expect_true(is_scope_on(list(package = "fooo"))) # include some, exclude some withr::local_envvar(structure("foo*", names = otel_emit_scopes_envvar)) withr::local_envvar(structure("foo?", names = otel_suppress_scopes_envvar)) expect_true(is_scope_on(list(name = "foo"))) expect_true(is_scope_on(list(package = "foo"))) expect_true(is_scope_on(list(name = "foobar"))) expect_true(is_scope_on(list(package = "foobar"))) expect_false(is_scope_on(list(name = "fooz"))) expect_false(is_scope_on(list(package = "fooz"))) }) otel/tests/testthat/test-api.R0000644000176200001440000004126415054311350016074 0ustar liggesuserstest_that("is_tracing_enabled", { fake(is_tracing_enabled, "get_tracer", list(is_enabled = function() FALSE)) expect_false(is_tracing_enabled()) fake(is_tracing_enabled, "get_tracer", function(name) stop("nope")) expect_snapshot(is_tracing_enabled()) fake( is_tracing_enabled_dev, "get_tracer", list(is_enabled = function() FALSE) ) expect_false(is_tracing_enabled_dev()) fake(is_tracing_enabled_dev, "get_tracer", function(name) stop("nope")) expect_snapshot(error = TRUE, is_tracing_enabled_dev()) }) test_that("is_logging_enabled", { fake( is_logging_enabled, "get_logger", structure( list(is_enabled = function(...) FALSE), class = "otel_logger_noop" ) ) expect_false(is_logging_enabled()) fake( is_logging_enabled, "get_logger", structure(list(is_enabled = function(...) TRUE), class = "otel_logger") ) expect_true(is_logging_enabled()) fake(is_logging_enabled, "get_logger", function(...) stop("nope")) expect_snapshot(is_logging_enabled()) fake( is_logging_enabled_dev, "get_logger", structure( list(is_enabled = function(...) FALSE), class = "otel_logger_noop" ) ) expect_false(is_logging_enabled_dev()) fake( is_logging_enabled_dev, "get_logger", structure(list(is_enabled = function(...) TRUE), class = "otel_logger") ) expect_true(is_logging_enabled_dev()) fake(is_logging_enabled_dev, "get_logger", function() stop("nope")) expect_snapshot(error = TRUE, is_logging_enabled_dev()) }) test_that("is_measuring_enabled", { fake( is_measuring_enabled, "get_meter", structure(list(is_enabled = function() FALSE), class = "otel_meter_noop") ) expect_false(is_measuring_enabled()) fake( is_measuring_enabled, "get_meter", structure(list(is_enabled = function() TRUE), class = "otel_meter") ) expect_true(is_measuring_enabled()) fake(is_measuring_enabled, "get_meter", function(...) stop("nope")) expect_snapshot(is_measuring_enabled()) fake( is_measuring_enabled_dev, "get_meter", structure(list(is_enabled = function() FALSE), class = "otel_meter_noop") ) expect_false(is_measuring_enabled_dev()) fake( is_measuring_enabled_dev, "get_meter", structure(list(is_enabled = function() TRUE), class = "otel_meter") ) expect_true(is_measuring_enabled_dev()) fake(is_measuring_enabled_dev, "get_meter", function(...) stop("nope")) expect_snapshot(error = TRUE, is_measuring_enabled_dev()) }) test_that("get_default_tracer", { local_otel_cache() withr::local_envvar( structure("none", names = default_traces_exporter_envvar_r) ) trc <- get_tracer() expect_s3_class(trc, "otel_tracer") expect_s3_class( get_default_tracer_provider(), "otel_tracer_provider_noop" ) the$tracer_provider <- NULL trc <- get_tracer_dev() expect_s3_class(trc, "otel_tracer") expect_s3_class( get_default_tracer_provider(), "otel_tracer_provider_noop" ) fake(get_tracer, "get_default_tracer_provider", function() stop("nope")) expect_snapshot({ trc <- get_tracer() }) expect_equal(trc, tracer_noop$new()) fake(get_tracer_dev, "get_default_tracer_provider", function() stop("x")) expect_snapshot(error = TRUE, { get_tracer_dev() }) }) test_that("get_default_logger", { local_otel_cache() withr::local_envvar( structure("none", names = default_logs_exporter_envvar_r) ) lgr <- get_logger() expect_s3_class(lgr, "otel_logger") expect_s3_class( get_default_logger_provider(), "otel_logger_provider_noop" ) the$logger_provider <- NULL lgr <- get_logger_dev() expect_s3_class(lgr, "otel_logger") expect_s3_class( get_default_logger_provider(), "otel_logger_provider_noop" ) fake(get_logger, "get_default_logger_provider", function() stop("nope")) expect_snapshot( lgr <- get_logger() ) expect_equal(lgr, logger_noop$new()) fake(get_logger_dev, "get_default_logger_provider", function() stop("x")) expect_snapshot(error = TRUE, { get_logger_dev() }) }) test_that("get_default_meter", { local_otel_cache() withr::local_envvar( structure("none", names = default_metrics_exporter_envvar_r) ) mtr <- get_meter() expect_s3_class(mtr, "otel_meter") expect_s3_class( get_default_meter_provider(), "otel_meter_provider_noop" ) the$meter_provider <- NULL mtr <- get_meter_dev() expect_s3_class(mtr, "otel_meter") expect_s3_class( get_default_meter_provider(), "otel_meter_provider_noop" ) fake(get_meter, "get_default_meter_provider", function() stop("nope")) expect_snapshot( mtr <- get_meter() ) expect_equal(mtr, meter_noop$new()) fake(get_meter_dev, "get_default_meter_provider", function() stop("x")) expect_snapshot(error = TRUE, { get_meter_dev() }) }) test_that("start_local_active_span", { local_otel_cache() withr::local_envvar( structure("none", names = default_traces_exporter_envvar_r) ) span <- start_local_active_span() expect_s3_class(span, "otel_span_noop") spand <- start_local_active_span_dev() expect_s3_class(spand, "otel_span_noop") fake(start_local_active_span, "get_tracer", function(...) stop("nope")) expect_snapshot({ span4 <- start_local_active_span() }) expect_s3_class(span4, "otel_span_noop") fake(start_local_active_span_dev, "get_tracer", function(...) stop("nope")) expect_snapshot(error = TRUE, { span4 <- start_local_active_span_dev() }) }) test_that("start_span", { local_otel_off() sess <- start_span() expect_s3_class(sess, "otel_span_noop") sessd <- start_span_dev() expect_s3_class(sessd, "otel_span_noop") fake(start_span, "get_tracer", function(...) stop("nope")) expect_snapshot(sessx <- start_span()) expect_s3_class(sessx, "otel_span_noop") fake(start_span_dev, "get_tracer", function(...) stop("nope")) expect_snapshot(error = TRUE, start_span_dev()) }) test_that("end_span", { local_otel_off() span <- start_local_active_span() expect_s3_class(span, "otel_span") end_span(span) end_span(span) span <- start_local_active_span() expect_s3_class(span, "otel_span") end_span_dev(span) end_span_dev(span) fake(end_span, "identity", function(...) stop("not yet")) expect_snapshot(end_span(span)) fake(end_span_dev, "identity", function(...) stop("not yet")) expect_snapshot(error = TRUE, end_span_dev(span)) }) test_that("local_active_span", { local_otel_off() sess <- get_tracer("org.r-lib.otel")$start_span() expect_silent(local_active_span(sess)) expect_silent(local_active_span_dev(sess)) sess$activate <- function(...) stop("no!") expect_snapshot(local_active_span(sess)) expect_snapshot(error = TRUE, local_active_span_dev(sess)) }) test_that("with_active_span", { local_otel_off() sess <- get_tracer("org.r-lib.otel")$start_span() expect_silent(ret <- with_active_span(sess, 1 + 1)) expect_equal(ret, 2) expect_silent(ret <- with_active_span_dev(sess, 1 + 1)) expect_equal(ret, 2) sess$activate <- function(...) stop("no!") expect_snapshot(ret <- with_active_span(sess, 1 + 1)) expect_equal(ret, 2) expect_snapshot(error = TRUE, with_active_span_dev(sess, 1 + 1)) }) test_that("get_current_span_context", { local_otel_cache() withr::local_envvar( structure("none", names = default_traces_exporter_envvar_r) ) spc <- get_active_span_context() expect_s3_class(spc, "otel_span_context") expect_s3_class(spc, "otel_span_context_noop") expect_false(spc$is_valid()) # recover from error fake(get_active_span_context, "get_tracer", function() stop("nope!")) expect_snapshot({ spc2 <- get_active_span_context() }) expect_s3_class(spc2, "otel_span_context_noop") # error fake(get_active_span_context_dev, "get_tracer", function() stop("nope!")) expect_snapshot(error = TRUE, { get_active_span_context_dev() }) # error 2 fake( get_active_span_context_dev, "get_tracer", function() list(get_active_span_context = function() stop("nope!")) ) expect_snapshot(error = TRUE, { get_active_span_context_dev() }) }) test_that("get_active_span", { local_otel_off() spn <- get_active_span() expect_s3_class(spn, "otel_span") expect_s3_class(spn, "otel_span_noop") expect_false(spn$get_context()$is_valid()) # recover from error fake(get_active_span, "get_tracer", function() stop("ouch!")) expect_snapshot({ spn2 <- get_active_span() }) expect_s3_class(spn2, "otel_span_noop") # error fake(get_active_span_dev, "get_tracer", function() stop("nope!")) expect_snapshot(error = TRUE, { get_active_span_dev() }) # error 2 fake( get_active_span_dev, "get_tracer", function() list(get_active_span = function() stop("nope!")) ) expect_snapshot(error = TRUE, { get_active_span_dev() }) }) test_that("log", { local_otel_cache() withr::local_envvar( structure("none", names = default_logs_exporter_envvar_r) ) lgr <- log("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_dev, "get_logger", function() list(log = function(...) stop("no"))) expect_snapshot(error = TRUE, { log_dev("nothing") }) }) test_that("log_trace", { local_otel_off() lgr <- log_trace("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_trace, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_trace("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_trace_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_trace_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_trace_dev("nothing") }) }) test_that("log_debug", { local_otel_off() lgr <- log_debug("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_debug, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_debug("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_debug_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_debug_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_debug_dev("nothing") }) }) test_that("log_info", { local_otel_off() lgr <- log_info("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_info, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_info("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_info_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_info_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_info_dev("nothing") }) }) test_that("log_warn", { local_otel_off() lgr <- log_warn("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_warn, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_warn("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_warn_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_warn_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_warn_dev("nothing") }) }) test_that("log_error", { local_otel_off() lgr <- log_error("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_error, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_error("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_error_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_error_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_error_dev("nothing") }) }) test_that("log_fatal", { local_otel_off() lgr <- log_fatal("log message going nowhere") expect_s3_class(lgr, "otel_logger_noop") # error fake(log_fatal, "get_logger", function() stop("denied!")) expect_snapshot({ lgr2 <- log_fatal("another nothing") }) expect_s3_class(lgr, "otel_logger_noop") lgr3 <- log_fatal_dev("Still nowhere") expect_s3_class(lgr3, "otel_logger_noop") # error fake(log_fatal_dev, "get_logger", function() { list(log = function(...) stop("no")) }) expect_snapshot(error = TRUE, { log_fatal_dev("nothing") }) }) test_that("counter_add", { local_otel_cache() withr::local_envvar( structure("none", names = default_metrics_exporter_envvar_r) ) mtr <- counter_add("cx") expect_s3_class(mtr, "otel_counter_noop") # error fake(counter_add, "get_meter", function() stop("not today")) expect_snapshot({ mtr2 <- counter_add("cx") }) expect_s3_class(mtr2, "otel_counter_noop") mtr3 <- counter_add_dev("cx") expect_s3_class(mtr3, "otel_counter_noop") # error fake(counter_add_dev, "invisible", function(x) stop("sorry")) expect_snapshot(error = TRUE, { counter_add_dev("cx") }) }) test_that("up_down_counter_add", { local_otel_cache() withr::local_envvar( structure("none", names = default_metrics_exporter_envvar_r) ) mtr <- up_down_counter_add("cx") expect_s3_class(mtr, "otel_up_down_counter_noop") # error fake(up_down_counter_add, "get_meter", function() stop("not today")) expect_snapshot({ mtr2 <- up_down_counter_add("cx") }) expect_s3_class(mtr2, "otel_up_down_counter_noop") mtr3 <- up_down_counter_add_dev("cx") expect_s3_class(mtr3, "otel_up_down_counter_noop") # error fake(up_down_counter_add_dev, "invisible", function(x) stop("sorry")) expect_snapshot(error = TRUE, { up_down_counter_add_dev("cx") }) }) test_that("histogram_record", { local_otel_cache() withr::local_envvar( structure("none", names = default_metrics_exporter_envvar_r) ) mtr <- histogram_record("cx") expect_s3_class(mtr, "otel_histogram_noop") # error fake(histogram_record, "get_meter", function() stop("not today")) expect_snapshot({ mtr2 <- histogram_record("cx") }) expect_s3_class(mtr2, "otel_histogram_noop") mtr3 <- histogram_record_dev("cx") expect_s3_class(mtr3, "otel_histogram_noop") # error fake(histogram_record_dev, "invisible", function(x) stop("sorry")) expect_snapshot(error = TRUE, { histogram_record_dev("cx") }) }) test_that("gauge_record", { local_otel_cache() withr::local_envvar( structure("none", names = default_metrics_exporter_envvar_r) ) mtr <- gauge_record("cx") expect_s3_class(mtr, "otel_gauge_noop") # error fake(gauge_record, "get_meter", function() stop("not today")) expect_snapshot({ mtr2 <- gauge_record("cx") }) expect_s3_class(mtr2, "otel_gauge_noop") mtr3 <- gauge_record_dev("cx") expect_s3_class(mtr3, "otel_gauge_noop") # error fake(gauge_record_dev, "invisible", function(x) stop("sorry")) expect_snapshot(error = TRUE, { gauge_record_dev("cx") }) }) test_that("pack_http_context", { local_otel_off() fake( pack_http_context, "get_tracer", list(get_active_span_context = function() { list(to_http_headers = function() c(FOO = "bar")) }) ) expect_equal(pack_http_context(), c(FOO = "bar")) fake( pack_http_context_dev, "get_tracer", list(get_active_span_context = function() { list(to_http_headers = function() c(FOO = "bar")) }) ) expect_equal(pack_http_context_dev(), c(FOO = "bar")) fake(pack_http_context, "get_tracer", function() stop("sorry")) expect_snapshot(pack_http_context()) fake(pack_http_context_dev, "get_tracer", function() stop("sorry")) expect_snapshot(error = TRUE, pack_http_context_dev()) }) test_that("extract_http_context", { local_otel_cache() withr::local_envvar( structure("none", names = default_traces_exporter_envvar_r) ) spc <- extract_http_context(c(traceparent = "something")) expect_s3_class(spc, "otel_span_context_noop") # error fake(extract_http_context, "get_tracer", function() stop("out of context")) expect_snapshot(spc2 <- extract_http_context(c("does not matter"))) expect_s3_class(spc2, "otel_span_context_noop") spc3 <- extract_http_context_dev(c("does not matter")) expect_s3_class(spc3, "otel_span_context_noop") # error fake( extract_http_context_dev, "get_tracer", function() list(extract_http_context = function(...) stop("no context")) ) expect_snapshot(error = TRUE, { extract_http_context_dev(c("does not matter")) }) }) otel/tests/testthat/helper.R0000644000176200001440000000144415022755455015636 0ustar liggesuserstest_pkg_root <- function() { pkg <- test_path("../../") if (!file.exists(file.path(pkg, "DESCRIPTION"))) { pkg <- file.path(pkg, "00_pkg_src", .packageName) } pkg } local_otel_cache <- function(.local_envir = parent.frame()) { otel_clean_cache() withr::defer(otel_clean_cache(), envir = .local_envir) } local_otel_off <- function(.local_envir = parent.frame()) { local_otel_cache(.local_envir = .local_envir) withr::local_envvar( structure( rep("none", 3), names = c( default_traces_exporter_envvar_r, default_logs_exporter_envvar_r, default_metrics_exporter_envvar_r ) ), .local_envir = .local_envir ) } transform_env_address <- function(x) { x <- sub("", ">", x) x } otel/tests/testthat/test-logger-provider-noop.R0000644000176200001440000000150315054313111021370 0ustar liggesuserstest_that("logger_provider_noop", { lp <- logger_provider_noop$new() expect_s3_class(lp, "otel_logger_provider") expect_s3_class(lp, "otel_logger_provider_noop") lgr <- lp$get_logger("test") expect_s3_class(lgr, "otel_logger") expect_s3_class(lgr, "otel_logger_noop") }) test_that("logger_noop", { lp <- logger_provider_noop$new() lgr <- lp$get_logger("test") expect_equal(lgr$trace(), lgr) expect_equal(lgr$debug(), lgr) expect_equal(lgr$info(), lgr) expect_equal(lgr$warn(), lgr) expect_equal(lgr$error(), lgr) expect_equal(lgr$fatal(), lgr) expect_equal(lgr$log(), lgr) expect_false(lgr$is_enabled()) expect_equal(lgr$get_minimum_severity(), c("maximumseverity" = 255L)) expect_equal(lgr$set_minimum_severity(10L), lgr) expect_equal(lgr$get_minimum_severity(), c("maximumseverity" = 255L)) }) otel/tests/testthat/test-as-attributes.R0000644000176200001440000000404715023740115020111 0ustar liggesuserstest_that("simple", { withr::local_envvar( OTEL_ATTRIBUTE_COUNT_LIMIT = NA_character_, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = NA_character_ ) ok <- list(a = "", b = FALSE, c = 1:3 / 2, d = 1:4) expect_equal(as_attributes(ok), ok) }) test_that("not a list", { expect_snapshot(error = TRUE, { as_attributes(1:10) }) }) test_that("count limit", { withr::local_envvar( OTEL_ATTRIBUTE_COUNT_LIMIT = 5, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = NA_character_ ) lst <- list(a = 1, b = 2, c = 3, d = 4, e = 5) lst2 <- list(a = 1, b = 2, c = 3, d = 4, e = 5, f = 6) expect_equal(as_attributes(lst), lst) expect_equal(as_attributes(lst2), lst) }) test_that("value length limit", { withr::local_envvar( OTEL_ATTRIBUTE_COUNT_LIMIT = NA_character_, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = 3 ) lst <- list(a = 1:3, b = as.character(1:3)) lst2 <- list(a = 1:10, b = as.character(1:10)) expect_equal(as_attributes(lst), lst) expect_equal(as_attributes(lst2), lst) }) test_that("fix bad names", { withr::local_envvar( OTEL_ATTRIBUTE_COUNT_LIMIT = NA_character_, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = NA_character_ ) expect_equal( as_attributes(list(1, 2, 3)), list("1" = 1, "2" = 2, "3" = 3) ) expect_equal( as_attributes(list(1, 2, 3)), list("1" = 1, "2" = 2, "3" = 3) ) expect_equal( as_attributes(list(a = 1, 2, a = 3)), list(a = 1, "2" = 2, a.1 = 3) ) }) test_that("non-finite real values", { expect_equal( as_attributes(list(a = c(1, NA_real_))), list(a = c("1", "NA")) ) expect_equal( as_attributes(list(a = c(1, NaN))), list(a = c("1", "NaN")) ) expect_equal( as_attributes(list(a = c(1, Inf))), list(a = c("1", "Inf")) ) expect_equal( as_attributes(list(a = c(1, -Inf))), list(a = c("1", "-Inf")) ) }) test_that("print unsupported types", { withr::local_envvar( OTEL_ATTRIBUTE_COUNT_LIMIT = NA_character_, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = NA_character_ ) expect_snapshot( as_attributes(list(mtcars[1:2, 1:4])) ) }) otel/tests/testthat/test-checks.R0000644000176200001440000000111314771510355016563 0ustar liggesuserstest_that("is_string", { expect_true(is_string("foo")) expect_true(is_string(c(name = "foo"))) expect_false(is_string(1)) expect_false(is_string(letters)) expect_false(is_string(NA_character_)) expect_false(is_string(character())) }) test_that("as_string", { expect_null(as_string(NULL)) expect_equal(as_string("foo"), "foo") expect_equal(as_string(c(a = "1")), c(a = "1")) s1 <- 1 s2 <- character() s3 <- letters[1:2] s4 <- NULL expect_snapshot(error = TRUE, { as_string(s1) as_string(s2) as_string(s3) as_string(s4, null = FALSE) }) }) otel/tests/testthat/test-meter-provider-noop.R0000644000176200001440000000240515054312334021235 0ustar liggesuserstest_that("meter_provider_noop", { mp <- meter_provider_noop$new() expect_s3_class(mp$get_meter("test"), "otel_meter_noop") expect_equal(mp$flush(), mp) expect_equal(mp$shutdown(), mp) expect_equal(mp$get_metrics(), list()) }) test_that("meter_noop", { mp <- meter_provider_noop$new() mtr <- mp$get_meter("test") expect_s3_class(mtr$create_counter("i1"), "otel_counter_noop") expect_s3_class(mtr$create_up_down_counter("i2"), "otel_up_down_counter_noop") expect_s3_class(mtr$create_histogram("i3"), "otel_histogram_noop") expect_s3_class(mtr$create_gauge("i4"), "otel_gauge_noop") }) test_that("counter_noop", { mp <- meter_provider_noop$new() mtr <- mp$get_meter("test") inst <- mtr$create_counter("i1") expect_equal(inst$add(), inst) }) test_that("up_down_counter_noop", { mp <- meter_provider_noop$new() mtr <- mp$get_meter("test") inst <- mtr$create_up_down_counter("i1") expect_equal(inst$add(), inst) }) test_that("histogram_noop", { mp <- meter_provider_noop$new() mtr <- mp$get_meter("test") inst <- mtr$create_histogram("i1") expect_equal(inst$record(), inst) }) test_that("gauge_noop", { mp <- meter_provider_noop$new() mtr <- mp$get_meter("test") inst <- mtr$create_gauge("i1") expect_equal(inst$record(), inst) }) otel/tests/testthat/test-no-eval.R0000644000176200001440000000347615037460144016676 0ustar liggesuserstest_that("attributes", { local_otel_off() expect_silent(start_span("sp", attributes = stop("oh!"))) expect_silent(start_local_active_span( "sp", attributes = stop("please ignore") )) expect_silent(get_meter("org.r-lib.otel")$create_counter("ctr")$add( "ctr", attributes = stop("don't mind me") )) expect_silent(get_meter("org.r-lib.otel")$create_gauge("gge")$record( attributes = stop("keep on") )) expect_silent(get_meter("org.r-lib.otel")$create_histogram("hst")$record( attributes = stop("and on") )) expect_silent(get_meter("org.r-lib.otel")$create_up_down_counter("udc")$add( "udc", attributes = stop("...") )) trc <- get_tracer() expect_silent(trc$start_span("sp", attributes = stop("never mind me"))) mtr <- get_meter() ctr <- mtr$create_counter("ctr") expect_silent(ctr$add(attributes = stop("not important"))) udc <- mtr$create_up_down_counter("udc") expect_silent(udc$add(attributes = stop("look away"))) hst <- mtr$create_histogram("hst") expect_silent(hst$record(attributes = stop("close your eyes"))) gge <- mtr$create_gauge("gge") expect_silent(gge$record(attributes = stop("no problem here"))) }) test_that("instrument description and unit", { local_otel_off() mtr <- get_meter() expect_silent(mtr$create_counter("ctr", description = stop("no!"))) expect_silent(mtr$create_counter("ctr", unit = stop("no!"))) expect_silent(mtr$create_up_down_counter("udc", description = stop("nah-ah"))) expect_silent(mtr$create_up_down_counter("udc", unit = stop("nah-ah"))) expect_silent(mtr$create_histogram("hst", description = stop("nay"))) expect_silent(mtr$create_histogram("hst", unit = stop("nay"))) expect_silent(mtr$create_gauge("gge", description = stop("not today"))) expect_silent(mtr$create_gauge("gge", unit = stop("not today"))) }) otel/tests/testthat/test-rtrace.R0000644000176200001440000000415615054310416016604 0ustar liggesuserstest_that("trace_namespace", { loadNamespace("cli") fake(trace_namespace, "trace_env", function(...) res <<- list(...)) res <- NULL expect_snapshot(trace_namespace("otel")) }) test_that("trace_env", { env <- new.env(parent = emptyenv()) env$f <- function() "dummy" env$obj <- "not-a-function" trace_env(env, "pkg") skip_on_covr() expect_snapshot( { print(env$f, useSource = FALSE) env$obj }, transform = transform_env_address, variant = if (Sys.getenv("TESTTHAT_COVERAGE") == "otel") "cov" else "nocov" ) }) test_that("integration test", { skip_on_cran() skip_on_covr() lib <- tempfile() on.exit(unlink(lib, recursive = TRUE), add = TRUE) mkdirp(lib) install.packages( test_path("fixtures/oteltest"), lib = lib, repos = NULL, type = "source", quiet = TRUE, INSTALL_opts = c("--no-staged-install", "--no-test-load") ) withr::local_libpaths(lib, action = "prefix") script <- system.file("runme.R", package = "oteltest") # test w/o instrumenting env_wo <- c(callr::rcmd_safe_env(), OTEL_TRACES_EXPORTER = "none") expect_snapshot({ callr::rscript(script, env = env_wo) }) # w/ ZCI traces <- tempfile(fileext = ".jsonl") on.exit(unlink(traces), add = TRUE) env <- c( callr::rcmd_safe_env(), OTEL_TRACES_EXPORTER = "otlp/file", OTEL_EXPORTER_OTLP_TRACES_FILE = traces, OTEL_R_INSTRUMENT_PKGS = "oteltest", OTEL_ENV = "dev" ) expect_snapshot({ callr::rscript(script, env = env) }) expect_true(file.exists(traces)) lns <- readLines(traces) spns <- lapply(lns, jsonlite::fromJSON, simplifyVector = FALSE) spns <- lapply(spns, function(x) { x$resourceSpans[[1]]$scopeSpans[[1]]$spans[[1]] }) # create a tree of spans ids <- map_chr(spns, "[[", "spanId") prns <- map_chr(spns, function(x) x$parentSpanId %||% NA_character_) children <- tapply(ids, prns, c, simplify = FALSE) spnstree <- data.frame( id = ids, children = I(unname(children[ids])), label = map_chr(spns, "[[", "name") ) root <- ids[is.na(prns)][1] expect_snapshot({ cli::tree(spnstree, root = root) }) }) otel/tests/testthat/helper-mock.R0000644000176200001440000000621414771512321016556 0ustar liggesusersfake <- local({ fake_through_tree <- function(tree, what, how) { for (d in tree) { for (parent in d) { parent_env <- parent[["parent_env"]] func_dict <- parent[["funcs"]] for (func_name in ls(func_dict, all.names = TRUE)) { func <- func_dict[[func_name]] func_env <- new.env(parent = environment(func)) what <- override_seperators(what, func_env) where_name <- override_seperators(func_name, parent_env) if (!is.function(how)) { assign(what, function(...) how, func_env) } else { assign(what, how, func_env) } environment(func) <- func_env locked <- exists(where_name, parent_env, inherits = FALSE) && bindingIsLocked(where_name, parent_env) if (locked) { baseenv()$unlockBinding(where_name, parent_env) } assign(where_name, func, parent_env) if (locked) { lockBinding(where_name, parent_env) } } } } } override_seperators <- function(name, env) { mangled_name <- NULL for (sep in c("::", "$")) { if (grepl(sep, name, fixed = TRUE)) { elements <- strsplit(name, sep, fixed = TRUE) mangled_name <- paste( elements[[1L]][1L], elements[[1L]][2L], sep = "XXX" ) stub_list <- c(mangled_name) if ("stub_list" %in% names(attributes(get(sep, env)))) { stub_list <- c(stub_list, attributes(get(sep, env))[["stub_list"]]) } create_new_name <- create_create_new_name_function( stub_list, env, sep ) assign(sep, create_new_name, env) } } mangled_name %||% name } backtick <- function(x) { encodeString(x, quote = "`", na.encode = FALSE) } create_create_new_name_function <- function(stub_list, env, sep) { force(stub_list) force(env) force(sep) create_new_name <- function(pkg, func) { pkg_name <- deparse(substitute(pkg)) func_name <- deparse(substitute(func)) for (stub in stub_list) { if (paste(pkg_name, func_name, sep = "XXX") == stub) { return(eval(parse(text = backtick(stub)), env)) } } # used to avoid recursively calling the replacement function eval_env <- new.env(parent = parent.frame()) assign(sep, eval(parse(text = paste0("`", sep, "`"))), eval_env) code <- paste(pkg_name, backtick(func_name), sep = sep) return(eval(parse(text = code), eval_env)) } attributes(create_new_name) <- list(stub_list = stub_list) create_new_name } build_function_tree <- function(test_env, where, where_name) { func_dict <- new.env() func_dict[[where_name]] <- where tree <- list( list( list(parent_env = test_env, funcs = func_dict) ) ) tree } fake <- function(where, what, how) { where_name <- deparse(substitute(where)) stopifnot(is.character(what), length(what) == 1) test_env <- parent.frame() tree <- build_function_tree(test_env, where, where_name) fake_through_tree(tree, what, how) } }) otel/tests/testthat/_snaps/0000755000176200001440000000000015054314766015515 5ustar liggesusersotel/tests/testthat/_snaps/rtrace.md0000644000176200001440000000175415054314767017327 0ustar liggesusers# trace_namespace Code trace_namespace("otel") Message i Instrumenting otel. # integration test Code callr::rscript(script, env = env_wo) Output runme in child1 in grandchild1 grandchild2 child1 out notthis child2 in grandchild1 grandchild2 child2 out runme out --- Code callr::rscript(script, env = env) Output runme in child1 in grandchild1 grandchild2 child1 out notthis child2 in grandchild1 grandchild2 child2 out runme out --- Code cli::tree(spnstree, root = root) Output oteltest::runme +-oteltest::child1 | +-oteltest::grandchild1 | \-oteltest::grandchild2 \-oteltest::child2 +-oteltest::grandchild1 \-oteltest::grandchild2 otel/tests/testthat/_snaps/print.md0000644000176200001440000000645015054314766017200 0ustar liggesusers# format.otel_tracer_privider Code get_default_tracer_provider() Output methods: get_tracer(name, version, schema_url, attributes) flush() get_spans() # format.otel_tracer Code get_default_tracer_provider()$get_tracer() Output methods: start_span(name, attributes, links, options) is_enabled() flush() # format.otel_span Code trc$start_span() Output name: methods: add_event(name, attributes, timestamp) end(options, status_code) get_context() is_recording() record_exception(error_condition, attributes, ...) set_attribute(name, value) set_status(status_code, description) update_name(name) # format.otel_span_context Code trc$start_span()$get_context() Output methods: get_span_id() get_trace_flags() get_trace_id() is_remote() is_sampled() is_valid() to_http_headers() # format.otel_logger_provider Code get_default_logger_provider() Output methods: get_logger(name, minimum_severity, version, schema_url, attributes) flush() # format.otel_logger Code get_default_logger_provider()$get_logger() Output methods: is_enabled() get_minimum_severity() set_minimum_severity(minimum_severity) log(msg, severity, span_context, attributes, ..., .envir) trace(msg, span_context, attributes, ..., .envir) debug(msg, span_context, attributes, ..., .envir) info(msg, span_context, attributes, ..., .envir) warn(msg, span_context, attributes, ..., .envir) error(msg, span_context, attributes, ..., .envir) fatal(msg, span_context, attributes, ..., .envir) # format.otel_meter_provider Code get_default_meter_provider() Output methods: get_meter(name, version, schema_url, attributes) flush(timeout) shutdown(timeout) get_metrics() # format.otel_meter Code get_default_meter_provider()$get_meter() Output methods: create_counter(name, description, unit) create_up_down_counter(name, description, unit) create_histogram(name, description, unit) create_gauge(name, description, unit) # format.otel_counter Code mtr$create_counter("ctr") Output methods: add(value, attributes, span_context) # format.otel_up_down_counter Code mtr$create_up_down_counter("ctr") Output methods: add(value, attributes, span_context) # format.otel_histogram Code mtr$create_histogram("hst") Output methods: record(value, attributes, span_context) # format.otel_gauge Code mtr$create_gauge("gge") otel/tests/testthat/_snaps/checks.md0000644000176200001440000000117715054314765017304 0ustar liggesusers# as_string Code as_string(s1) Condition Error in `as_string()`: ! Invalid argument: s1 must be a string scalar, but it is a number. Code as_string(s2) Condition Error in `as_string()`: ! Invalid argument: s2 must be a string scalar, but it is an empty character vector. Code as_string(s3) Condition Error in `as_string()`: ! Invalid argument: s3 must be a string scalar, but it is a character vector. Code as_string(s4, null = FALSE) Condition Error in `as_string()`: ! Invalid argument: s4 must be a string scalar, but it is NULL. otel/tests/testthat/_snaps/spelling.md0000644000176200001440000000030215054314770017642 0ustar liggesusers# spelling Code spelling::spell_check_package(pkg) Message DESCRIPTION does not contain 'Language' field. Defaulting to 'en-US'. Output No spelling errors found. otel/tests/testthat/_snaps/defaults.md0000644000176200001440000001055715054314765017655 0ustar liggesusers# get_default_tracer_provider Code tp <- get_default_tracer_provider() Message OpenTelemetry error: nope --- Code get_default_tracer_provider_dev() Condition Error in `setup_default_tracer_provider()`: ! nope # setup_default_tracer_provider Code setup_default_tracer_provider() Condition Warning in `setup_default_tracer_provider()`: OpenTelemetry: Jaeger trace exporter is not supported yet --- Code setup_default_tracer_provider() Condition Warning in `setup_default_tracer_provider()`: OpenTelemetry: Zipkin trace exporter is not supported yet --- Code setup_default_tracer_provider() Condition Error in `setup_default_tracer_provider()`: ! Unknown OpenTelemetry exporter from OTEL_R_TRACES_EXPORTER environment variable: invalid --- Code setup_default_tracer_provider() Condition Error in `setup_default_tracer_provider()`: ! Cannot set trace exporter bad_package::tracer_provider from OTEL_R_TRACES_EXPORTER environment variable, cannot load package bad_package. --- Code setup_default_tracer_provider() Condition Error in `setup_default_tracer_provider()`: ! Cannot set trace exporter otel::no_such_object from OTEL_R_TRACES_EXPORTER environment variable, cannot find provider no_such_object in package otel. --- Code setup_default_tracer_provider() Condition Error in `setup_default_tracer_provider()`: ! Cannot set trace exporter otel::is_string from OTEL_R_TRACES_EXPORTER environment variable, it is not a list or environment with a 'new' member. # get_default_logger_provider Code tp <- get_default_logger_provider() Message OpenTelemetry error: nope --- Code get_default_logger_provider_dev() Condition Error in `setup_default_logger_provider()`: ! nope # setup_default_logger_provider Code setup_default_logger_provider() Condition Error in `setup_default_logger_provider()`: ! Unknown OpenTelemetry exporter from OTEL_R_LOGS_EXPORTER environment variable: invalid --- Code setup_default_logger_provider() Condition Error in `setup_default_logger_provider()`: ! Cannot set logs exporter bad_package::logger_provider from OTEL_R_LOGS_EXPORTER environment variable, cannot load package bad_package. --- Code setup_default_logger_provider() Condition Error in `setup_default_logger_provider()`: ! Cannot set logs exporter otel::no_such_object from OTEL_R_LOGS_EXPORTER environment variable, cannot find provider no_such_object in package otel. --- Code setup_default_logger_provider() Condition Error in `setup_default_logger_provider()`: ! Cannot set logs exporter otel::is_string from OTEL_R_LOGS_EXPORTER environment variable, it is not a list or environment with a 'new' member. # get_default_meter_provider Code tp <- get_default_meter_provider() Message OpenTelemetry error: nope --- Code get_default_meter_provider_dev() Condition Error in `setup_default_meter_provider()`: ! nope # setup_default_meter_provider Code setup_default_meter_provider() Condition Warning in `setup_default_meter_provider()`: OpenTelemetry: Prometheus trace exporter is not supported yet --- Code setup_default_meter_provider() Condition Error in `setup_default_meter_provider()`: ! Unknown OpenTelemetry exporter from OTEL_R_METRICS_EXPORTER environment variable: invalid --- Code setup_default_meter_provider() Condition Error in `setup_default_meter_provider()`: ! Cannot set metrics exporter bad_package::meter_provider from OTEL_R_METRICS_EXPORTER environment variable, cannot load package bad_package. --- Code setup_default_meter_provider() Condition Error in `setup_default_meter_provider()`: ! Cannot set metrics exporter otel::no_such_object from OTEL_R_METRICS_EXPORTER environment variable, cannot find provider no_such_object in package otel. --- Code setup_default_meter_provider() Condition Error in `setup_default_meter_provider()`: ! Cannot set metrics exporter otel::is_string from OTEL_R_METRICS_EXPORTER environment variable, it is not a list or environment with a 'new' member. otel/tests/testthat/_snaps/onload.md0000644000176200001440000000204515054314766017314 0ustar liggesusers# otel_save_cache, otel_restore_cache Code as.list(env) Output $instruments NULL $meter_provider [1] 1 2 3 4 5 6 7 8 9 10 $tracer_provider [1] "bar" $logger_provider NULL $tracer_app NULL --- Code as.list(the) Output $instruments NULL $meter_provider [1] 1 2 3 4 5 6 7 8 9 10 $tracer_provider [1] "bar" $logger_provider NULL $mode [1] "prod" $tracer_app NULL # setup_r_trace Code res Output [[1]] [1] "ok" [[2]] NULL [[3]] NULL --- Code res Output [[1]] [1] "ok" [[2]] [1] "inc*" [[3]] [1] "exclude.*" --- Code res[[1]] Output [1] "UserHook::ok::onLoad" Code body(res[[2]]) Output trace_namespace(pkg, inc, exc) otel/tests/testthat/_snaps/api.md0000644000176200001440000001354315054314765016615 0ustar liggesusers# is_tracing_enabled Code is_tracing_enabled() Message OpenTelemetry error: nope Output [1] FALSE --- Code is_tracing_enabled_dev() Condition Error in `get_tracer()`: ! nope # is_logging_enabled Code is_logging_enabled() Message OpenTelemetry error: nope Output [1] FALSE --- Code is_logging_enabled_dev() Condition Error in `get_logger()`: ! unused argument (logger) # is_measuring_enabled Code is_measuring_enabled() Message OpenTelemetry error: nope Output [1] FALSE --- Code is_measuring_enabled_dev() Condition Error in `get_meter()`: ! nope # get_default_tracer Code trc <- get_tracer() Message OpenTelemetry error: nope --- Code get_tracer_dev() Condition Error in `get_default_tracer_provider()`: ! x # get_default_logger Code lgr <- get_logger() Message OpenTelemetry error: nope --- Code get_logger_dev() Condition Error in `get_default_logger_provider()`: ! x # get_default_meter Code mtr <- get_meter() Message OpenTelemetry error: nope --- Code get_meter_dev() Condition Error in `get_default_meter_provider()`: ! x # start_local_active_span Code span4 <- start_local_active_span() Message OpenTelemetry error: nope --- Code span4 <- start_local_active_span_dev() Condition Error in `get_tracer()`: ! nope # start_span Code sessx <- start_span() Message OpenTelemetry error: nope --- Code start_span_dev() Condition Error in `get_tracer()`: ! nope # end_span Code end_span(span) Message OpenTelemetry error: not yet --- Code end_span_dev(span) Condition Error in `identity()`: ! not yet # local_active_span Code local_active_span(sess) Message OpenTelemetry error: no! --- Code local_active_span_dev(sess) Condition Error in `span$activate()`: ! no! # with_active_span Code ret <- with_active_span(sess, 1 + 1) Message OpenTelemetry error: no! --- Code with_active_span_dev(sess, 1 + 1) Condition Error in `span$activate()`: ! no! # get_current_span_context Code spc2 <- get_active_span_context() Message OpenTelemetry error: nope! --- Code get_active_span_context_dev() Condition Error in `get_tracer()`: ! nope! --- Code get_active_span_context_dev() Condition Error in `trc$get_active_span_context()`: ! nope! # get_active_span Code spn2 <- get_active_span() Message OpenTelemetry error: ouch! --- Code get_active_span_dev() Condition Error in `get_tracer()`: ! nope! --- Code get_active_span_dev() Condition Error in `trc$get_active_span()`: ! nope! # log Code lgr2 <- log("another nothing") Message OpenTelemetry error: denied! --- Code log_dev("nothing") Condition Error in `logger$log()`: ! no # log_trace Code lgr2 <- log_trace("another nothing") Message OpenTelemetry error: denied! --- Code log_trace_dev("nothing") Condition Error in `logger$log()`: ! no # log_debug Code lgr2 <- log_debug("another nothing") Message OpenTelemetry error: denied! --- Code log_debug_dev("nothing") Condition Error in `logger$log()`: ! no # log_info Code lgr2 <- log_info("another nothing") Message OpenTelemetry error: denied! --- Code log_info_dev("nothing") Condition Error in `logger$log()`: ! no # log_warn Code lgr2 <- log_warn("another nothing") Message OpenTelemetry error: denied! --- Code log_warn_dev("nothing") Condition Error in `logger$log()`: ! no # log_error Code lgr2 <- log_error("another nothing") Message OpenTelemetry error: denied! --- Code log_error_dev("nothing") Condition Error in `logger$log()`: ! no # log_fatal Code lgr2 <- log_fatal("another nothing") Message OpenTelemetry error: denied! --- Code log_fatal_dev("nothing") Condition Error in `logger$log()`: ! no # counter_add Code mtr2 <- counter_add("cx") Message OpenTelemetry error: not today --- Code counter_add_dev("cx") Condition Error in `invisible()`: ! sorry # up_down_counter_add Code mtr2 <- up_down_counter_add("cx") Message OpenTelemetry error: not today --- Code up_down_counter_add_dev("cx") Condition Error in `invisible()`: ! sorry # histogram_record Code mtr2 <- histogram_record("cx") Message OpenTelemetry error: not today --- Code histogram_record_dev("cx") Condition Error in `invisible()`: ! sorry # gauge_record Code mtr2 <- gauge_record("cx") Message OpenTelemetry error: not today --- Code gauge_record_dev("cx") Condition Error in `invisible()`: ! sorry # pack_http_context Code pack_http_context() Message OpenTelemetry error: sorry Output named character(0) --- Code pack_http_context_dev() Condition Error in `get_tracer()`: ! sorry # extract_http_context Code spc2 <- extract_http_context(c("does not matter")) Message OpenTelemetry error: out of context --- Code extract_http_context_dev(c("does not matter")) Condition Error in `trc$extract_http_context()`: ! no context otel/tests/testthat/_snaps/formatting.md0000644000176200001440000000021415054314765020205 0ustar liggesusers# code formatting Code invisible(processx::run("air", c("format", "--check", pkg), echo = TRUE, error_on_status = FALSE)) otel/tests/testthat/_snaps/cov/0000755000176200001440000000000015054310152016265 5ustar liggesusersotel/tests/testthat/_snaps/cov/rtrace.md0000644000176200001440000000203615054314767020110 0ustar liggesusers# trace_env Code print(env$f, useSource = FALSE) Output new("functionWithTrace", .Data = function () { on.exit(.doTrace({ .__cov_otel_rtrace[33] try(.__span$deactivate(.__scope)) .__cov_otel_rtrace[34] try(.__span$end()) })) { .doTrace({ .__cov_otel_rtrace[25] .__span <- otel::start_span("pkg::f", tracer = "org.r-lib.otel") .__cov_otel_rtrace[26] .__scope <- .__span$activate(NULL) }) "dummy" } }, original = function () "dummy", source = ) > attr(,"original") function () "dummy" > attr(,"source") attr(,"class") [1] "functionWithTrace" attr(,"class")attr(,"package") [1] "methods" Code env$obj Output [1] "not-a-function" otel/tests/testthat/_snaps/utils.md0000644000176200001440000000256115054314770017176 0ustar liggesusers# errmsg Code errmsg("this is a ", "message instead of an error") Message this is a message instead of an error # msg Code msg("just being busy") Message i just being busy --- Code msg("nothing to see here") # glob_filter Code glob_filter(fns, include = "default_*") Output [1] "default_logs_exporter_envvar" "default_logs_exporter_envvar_r" Code glob_filter(fns, include = c("default_*", "?auge")) Output [1] "default_logs_exporter_envvar" "default_logs_exporter_envvar_r" [3] "gauge" Code glob_filter(fns, exclude = c("errmsg", "get_*")) Output [1] "default_logs_exporter_envvar" "default_logs_exporter_envvar_r" [3] "friendly_type" "gauge" Code glob_filter(fns, include = c("default_*", "?auge"), exclude = "*_r") Output [1] "default_logs_exporter_envvar" "gauge" # get_env_count Code get_env_count("FOO", -1L) Condition Error in `get_env_count()`: ! Invalid `default` in `get_env_count()`, must be a non-negative integer scalar. Code get_env_count("FOO", "bad-default") Condition Error in `get_env_count()`: ! Invalid `default` in `get_env_count()`, must be a non-negative integer scalar. otel/tests/testthat/_snaps/nocov/0000755000176200001440000000000015054310437016630 5ustar liggesusersotel/tests/testthat/_snaps/nocov/rtrace.md0000644000176200001440000000160215054310443020426 0ustar liggesusers# trace_env Code print(env$f, useSource = FALSE) Output new("functionWithTrace", .Data = function () { on.exit(.doTrace({ try(.__span$deactivate(.__scope)) try(.__span$end()) })) { .doTrace({ .__span <- otel::start_span("pkg::f", tracer = "org.r-lib.otel") .__scope <- .__span$activate(NULL) }) "dummy" } }, original = function () "dummy", source = ) > attr(,"original") function () "dummy" > attr(,"source") attr(,"class") [1] "functionWithTrace" attr(,"class")attr(,"package") [1] "methods" Code env$obj Output [1] "not-a-function" otel/tests/testthat/_snaps/as-attributes.md0000644000176200001440000000061215054314765020624 0ustar liggesusers# not a list Code as_attributes(1:10) Condition Error in `as_attributes()`: ! Invalid argument: `x` must be a list in `as_attributes()`. # print unsupported types Code as_attributes(list(mtcars[1:2, 1:4])) Output $`1` [1] " mpg cyl disp hp" "Mazda RX4 21 6 160 110" [3] "Mazda RX4 Wag 21 6 160 110" otel/tests/testthat/_snaps/tracer-provider-noop.md0000644000176200001440000000013715054314770022114 0ustar liggesusers# span_context_noop Code spc$to_http_headers() Output named character(0) otel/tests/testthat/test-tracer-provider-noop.R0000644000176200001440000000355415054314452021412 0ustar liggesuserstest_that("tracer_provider_noop", { tp <- tracer_provider_noop$new() expect_s3_class(tp, "otel_tracer_provider") expect_s3_class(tp, "otel_tracer_provider_noop") trc <- tp$get_tracer("test") expect_s3_class(trc, "otel_tracer") expect_s3_class(trc, "otel_tracer_noop") expect_equal(tp$flush(), tp) expect_equal(tp$get_spans(), list()) }) test_that("tracer_noop", { tp <- tracer_provider_noop$new() trc <- tp$get_tracer("test") spn <- trc$start_span() expect_s3_class(spn, "otel_span") expect_s3_class(spn, "otel_span_noop") expect_s3_class(trc$get_active_span_context(), "otel_span_context_noop") expect_s3_class(trc$get_active_span(), "otel_span_noop") expect_false(trc$is_enabled()) expect_equal(trc$flush(), trc) expect_s3_class(trc$extract_http_context(), "otel_span_context_noop") }) test_that("span_noop", { tp <- tracer_provider_noop$new() trc <- tp$get_tracer("test") spn <- trc$start_span() expect_s3_class(spn$get_context(), "otel_span_context_noop") expect_false(spn$is_valid()) expect_false(spn$is_recording()) expect_equal(spn$set_attribute("key", "value"), spn) expect_equal(spn$add_event("name"), spn) expect_equal(spn$add_link(spn), spn) expect_equal(spn$set_status("ok"), spn) expect_equal(spn$update_name("new"), spn) expect_equal(spn$record_exception(), spn) expect_equal(spn$activate(), spn) expect_equal(spn$deactivate(), spn) expect_equal(spn$end(), spn) }) test_that("span_context_noop", { tp <- tracer_provider_noop$new() trc <- tp$get_tracer("test") spn <- trc$start_span() spc <- spn$get_context() expect_false(spc$is_valid()) expect_equal(spc$get_trace_flags(), list()) expect_equal(spc$get_trace_id(), invalid_trace_id) expect_equal(spc$get_span_id(), invalid_span_id) expect_false(spc$is_remote()) expect_false(spc$is_sampled()) expect_snapshot({ spc$to_http_headers() }) }) otel/tests/testthat/test-formatting.R0000644000176200001440000000132315033256363017476 0ustar liggesuserstest_that("code formatting", { skip_on_cran() skip_on_covr() # always run locally, but on the CI only on macOS if (Sys.getenv("CI") != "" && Sys.info()[["sysname"]] != "Darwin") { skip("Only run code formatting check on macOS") } pkg <- test_path("../../") if (!file.exists(file.path(pkg, "DESCRIPTION"))) { pkg <- file.path(pkg, "00_pkg_src", .packageName) file.copy(file.path(pkg, "inst", "air.toml"), pkg) on.exit(unlink(file.path(pkg, "air.toml")), add = TRUE) } if (Sys.which("air") == "") { stop("Could not find air installation") } expect_snapshot(invisible(processx::run( "air", c("format", "--check", pkg), echo = TRUE, error_on_status = FALSE ))) }) otel/tests/testthat/test-api-dev.R0000644000176200001440000000112415044424102016636 0ustar liggesuserstest_that("dev API is up to date", { testthat::skip_on_covr() skip_on_cran() tmp <- tempfile() tmp2 <- tempfile() on.exit(unlink(c(tmp, tmp2)), add = TRUE) withr::local_envvar(OTEL_DEV_API_OUTPUT_FILE = tmp) pkg <- test_pkg_root() withr::local_dir(pkg) # this does not work in the installed package if (!file.exists("tools/template/dev.R")) { testthat::skip("does not work in installed package") } callr::rscript("tools/template/dev.R", show = FALSE) crt <- readLines(file.path("R", "api-dev.R"), warn = FALSE) upd <- readLines(tmp) expect_equal(upd, crt) }) otel/tests/testthat/test-defaults.R0000644000176200001440000002547715040654070017146 0ustar liggesuserstest_that("set_default_service_name", { withr::local_envvar(OTEL_SERVICE_NAME = "ok") set_default_service_name() expect_equal(get_env("OTEL_SERVICE_NAME"), "ok") withr::local_envvar(OTEL_SERVICE_NAME = NA_character_) set_default_service_name() expect_equal(get_env("OTEL_SERVICE_NAME"), "R") }) test_that("get_default_tracer_provider", { local_otel_cache() the$tracer_provider <- "foobar" expect_equal(get_default_tracer_provider(), "foobar") expect_equal(get_default_tracer_provider_dev(), "foobar") fake( get_default_tracer_provider, "setup_default_tracer_provider", function() { the$tracer_provider <- "new" } ) fake( get_default_tracer_provider_dev, "setup_default_tracer_provider", function() { the$tracer_provider <- "new" } ) expect_equal(get_default_tracer_provider(), "foobar") expect_equal(get_default_tracer_provider_dev(), "foobar") the$tracer_provider <- NULL expect_equal(get_default_tracer_provider(), "new") expect_equal(get_default_tracer_provider_dev(), "new") fake( get_default_tracer_provider, "setup_default_tracer_provider", function() stop("nope") ) fake( get_default_tracer_provider_dev, "setup_default_tracer_provider", function() stop("nope") ) the$tracer_provider <- NULL expect_snapshot({ tp <- get_default_tracer_provider() }) expect_s3_class(tp, "otel_tracer_provider_noop") expect_snapshot(error = TRUE, { get_default_tracer_provider_dev() }) }) test_that("setup_default_tracer_provider", { skip_on_cran() local_otel_cache() set_ev <- function(x, wh = c("r", "generic", "both")) { wh <- match.arg(wh) ev <- c( if (wh %in% c("r", "both")) { structure(x, names = default_traces_exporter_envvar_r) }, if (wh %in% c("generic", "both")) { structure(x, names = default_traces_exporter_envvar) } ) withr::local_envvar(ev, .local_envir = parent.frame()) } set_ev(NA_character_, "both") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_noop") set_ev("none") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_noop") set_ev("console") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_stdstream") set_ev("stdout") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_stdstream") set_ev("stderr") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_stdstream") set_ev("otlp") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_http") set_ev("otlp/file") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_file") set_ev("http") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_http") set_ev("jaeger") expect_snapshot(setup_default_tracer_provider()) expect_s3_class(the$tracer_provider, "otel_tracer_provider_noop") set_ev("zipkin") expect_snapshot(setup_default_tracer_provider()) expect_s3_class(the$tracer_provider, "otel_tracer_provider_noop") set_ev("invalid") expect_snapshot(error = TRUE, { setup_default_tracer_provider() }) # fall back to generic env var set_ev(NA_character_) set_ev("http", "generic") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_http") set_ev("otelsdk::tracer_provider_http") setup_default_tracer_provider() expect_s3_class(the$tracer_provider, "otel_tracer_provider_http") set_ev(NA_character_, "both") set_ev("bad_package::tracer_provider") expect_snapshot(error = TRUE, { setup_default_tracer_provider() }) set_ev("otel::no_such_object") expect_snapshot(error = TRUE, { setup_default_tracer_provider() }) set_ev("otel::is_string") expect_snapshot(error = TRUE, { setup_default_tracer_provider() }) }) test_that("get_default_logger_provider", { local_otel_cache() the$logger_provider <- "foobar" expect_equal(get_default_logger_provider(), "foobar") expect_equal(get_default_logger_provider_dev(), "foobar") fake( get_default_logger_provider, "setup_default_logger_provider", function() { the$logger_provider <- "new" } ) fake( get_default_logger_provider_dev, "setup_default_logger_provider", function() { the$logger_provider <- "new" } ) expect_equal(get_default_logger_provider(), "foobar") expect_equal(get_default_logger_provider_dev(), "foobar") the$logger_provider <- NULL expect_equal(get_default_logger_provider(), "new") expect_equal(get_default_logger_provider_dev(), "new") fake( get_default_logger_provider, "setup_default_logger_provider", function() stop("nope") ) fake( get_default_logger_provider_dev, "setup_default_logger_provider", function() stop("nope") ) the$logger_provider <- NULL expect_snapshot({ tp <- get_default_logger_provider() }) expect_s3_class(tp, "otel_logger_provider_noop") expect_snapshot(error = TRUE, { get_default_logger_provider_dev() }) }) test_that("setup_default_logger_provider", { skip_on_cran() local_otel_cache() set_ev <- function(x, wh = c("r", "generic", "both")) { wh <- match.arg(wh) ev <- c( if (wh %in% c("r", "both")) { structure(x, names = default_logs_exporter_envvar_r) }, if (wh %in% c("generic", "both")) { structure(x, names = default_logs_exporter_envvar) } ) withr::local_envvar(ev, .local_envir = parent.frame()) } set_ev(NA_character_, "both") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_noop") set_ev("none") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_noop") set_ev("console") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_stdstream") set_ev("stdout") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_stdstream") set_ev("stderr") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_stdstream") set_ev("otlp/file") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_file") set_ev("otlp") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_http") set_ev("http") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_http") set_ev("invalid") expect_snapshot(error = TRUE, { setup_default_logger_provider() }) # fall back to generic env var set_ev(NA_character_) set_ev("http", "generic") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_http") set_ev("otelsdk::logger_provider_http") setup_default_logger_provider() expect_s3_class(the$logger_provider, "otel_logger_provider_http") set_ev(NA_character_, "both") set_ev("bad_package::logger_provider") expect_snapshot(error = TRUE, { setup_default_logger_provider() }) set_ev("otel::no_such_object") expect_snapshot(error = TRUE, { setup_default_logger_provider() }) set_ev("otel::is_string") expect_snapshot(error = TRUE, { setup_default_logger_provider() }) }) test_that("get_default_meter_provider", { local_otel_cache() the$meter_provider <- "foobar" expect_equal(get_default_meter_provider(), "foobar") expect_equal(get_default_meter_provider_dev(), "foobar") fake( get_default_meter_provider, "setup_default_meter_provider", function() { the$meter_provider <- "new" } ) fake( get_default_meter_provider_dev, "setup_default_meter_provider", function() { the$meter_provider <- "new" } ) expect_equal(get_default_meter_provider(), "foobar") expect_equal(get_default_meter_provider_dev(), "foobar") the$meter_provider <- NULL expect_equal(get_default_meter_provider(), "new") expect_equal(get_default_meter_provider_dev(), "new") fake( get_default_meter_provider, "setup_default_meter_provider", function() stop("nope") ) fake( get_default_meter_provider_dev, "setup_default_meter_provider", function() stop("nope") ) the$meter_provider <- NULL expect_snapshot({ tp <- get_default_meter_provider() }) expect_s3_class(tp, "otel_meter_provider_noop") expect_snapshot(error = TRUE, { get_default_meter_provider_dev() }) }) test_that("setup_default_meter_provider", { skip_on_cran() local_otel_cache() set_ev <- function(x, wh = c("r", "generic", "both")) { wh <- match.arg(wh) ev <- c( if (wh %in% c("r", "both")) { structure(x, names = default_metrics_exporter_envvar_r) }, if (wh %in% c("generic", "both")) { structure(x, names = default_metrics_exporter_envvar) } ) withr::local_envvar(ev, .local_envir = parent.frame()) } set_ev(NA_character_, "both") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_noop") set_ev("none") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_noop") set_ev("console") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_stdstream") set_ev("stdout") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_stdstream") set_ev("stderr") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_stdstream") set_ev("otlp") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_http") set_ev("otlp/file") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_file") set_ev("http") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_http") set_ev("prometheus") expect_snapshot(setup_default_meter_provider()) expect_s3_class(the$meter_provider, "otel_meter_provider_noop") set_ev("invalid") expect_snapshot(error = TRUE, { setup_default_meter_provider() }) # fall back to generic env var set_ev(NA_character_) set_ev("http", "generic") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_http") set_ev("otelsdk::meter_provider_http") setup_default_meter_provider() expect_s3_class(the$meter_provider, "otel_meter_provider_http") set_ev(NA_character_, "both") set_ev("bad_package::meter_provider") expect_snapshot(error = TRUE, { setup_default_meter_provider() }) set_ev("otel::no_such_object") expect_snapshot(error = TRUE, { setup_default_meter_provider() }) set_ev("otel::is_string") expect_snapshot(error = TRUE, { setup_default_meter_provider() }) }) otel/tests/testthat.R0000644000176200001440000000060414771456720014357 0ustar liggesusers# This file is part of the standard setup for testthat. # It is recommended that you do not modify it. # # Where should you do additional test configuration? # Learn more about the roles of various files in: # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview # * https://testthat.r-lib.org/articles/special-files.html library(testthat) library(otel) test_check("otel") otel/MD50000644000176200001440000001534515054325537011546 0ustar liggesusersff098713026f35a0b389f9399d2a8bb9 *DESCRIPTION e9d10ebc667bbdeabee064034b9af4c4 *LICENSE 874853ae0d8a6fe89b873130f7883ef1 *NAMESPACE 3d4de39386dcc37ee27b70d046a6f0dc *NEWS.md a50abf0846d6210700263e0d153a8d3e *R/api-dev.R 1e9a8c2e0c2831cf89f72c1244a639b9 *R/api.R 46647d95f1fdcc81623757ed68c2fd8d *R/as-attributes.R 21d338e0d3def92503801aa858e8632a *R/checks.R 33c572930d0bcfcf41d7ca85f160f5f6 *R/constants.R 7c63df0aaa77628095a3ba83e97f2ed7 *R/defaults.R fd2e37be8508dfc9c3b1fb56036af90f *R/docs.R b4e37496d34a0b9812aaf90060fc9630 *R/friendly-type.R da7f90e8d69d6ae25669a4693d9c8832 *R/logger-provider-noop.R 2268126530c9890e438bbd03da4c9d19 *R/meter-provider-noop.R 9625e188f922351d95c9b1610ebba462 *R/onload.R 0d3431e07afc534fc6931548f5843e04 *R/print.R aa128a7f7cf14ba030e65810c013a7ce *R/rtrace.R 6285afec083daf4512217b0b0ceaf099 *R/tracer-name.R 1d09cdfbe8e0c9e1022b0b5fe2474ebc *R/tracer-provider-noop.R ae9cc634cfe3aba598b1f98428b3a0ab *R/utils.R d998a43a4852e1af855ff2b5ff7842b0 *README.md 384b87518f7dda726968a0c4a6a8d74e *inst/WORDLIST d69a62170da5d6080fffc4efb506f145 *inst/air.toml 12b70a3d150750bf0070b1e5a01b2d61 *inst/dox/Architecture.Rmd 51a3ca2a31ca99731925fd191ead0052 *inst/dox/ev-exporters.Rmd 3ceff523a25c941df1d3313655196248 *inst/dox/ev-others.Rmd 90d5a3f423388dc57fbe4993a2e88d74 *inst/dox/ev-suppress.Rmd 4455e1333c8dff2fc4620ffcec1ed894 *inst/dox/ev-zci.Rmd 388a56583992cc85a91e78b194b7a358 *inst/dox/features.Rmd 46ac0d4ab003aae01dcca79e3f1903f9 *inst/dox/gs.Rmd 0817c89dc90607a12e7fa735cbdb7793 *inst/dox/intro.Rmd 1b73bf9704f4d186e7be4d1c08ac8bdb *inst/dox/packages.Rmd 669e5d31caf23e4cfb4d9b6afdd0678f *inst/dox/reference-docs.Rmd 11544f14019d8af0c04e8c140e33ef45 *inst/dox/repositories.Rmd 92883274a393f995e6a6c9f1dd95f6de *inst/dox/status.Rmd dd48d4893cd97cf16f71566c81cace33 *inst/dox/version-support.Rmd 6bb29d3f330c0b37c2a4c416366ca851 *man/as_attributes.Rd 8b10729c12b798fe230403968cffb311 *man/counter_add.Rd b204d9769fd0d78eea31086e7f3b4a26 *man/default_tracer_name.Rd 05a513441a6db9ec1a48d0815c60ab2b *man/end_span.Rd 79a67115507dd251b717bd9c3133da39 *man/environmentvariables.Rd 8ca28104b5fdd27e60be39d46d47e651 *man/extract_http_context.Rd 7cd62611171f81efa1f9859ae8653ae7 *man/gauge_record.Rd a846fef25be100a11f45bd362d710c1c *man/get_active_span.Rd 1ee6e84d2949ac30a20f3117905a60a3 *man/get_active_span_context.Rd aba6f38d174183294be992eb2427f1e1 *man/get_default_logger_provider.Rd dd36474a0adc3dcbe97d6cd052feedeb *man/get_default_meter_provider.Rd 76e477a5528e8118408f0ad0be1eed22 *man/get_default_tracer_provider.Rd 04d5cc9a77d0effad53ca5542e5749ce *man/get_logger.Rd d7d5164e69be7bbd7f1587e085a8a10f *man/get_meter.Rd 28f184ba5a523aff13b8ee7a5c35018b *man/get_tracer.Rd 1ec3cb9f1ab298c3b4b86fc961323e02 *man/gettingstarted.Rd d34de52c59aabc6591ac42c938f2ee40 *man/histogram_record.Rd a3afaa557fe132508bc0fdb7796503e0 *man/is_logging_enabled.Rd c113565b67b3ec9b5b3d2be67cdf82c4 *man/is_measuring_enabled.Rd a0577eddd1d236c8f3016e5bfd251bec *man/is_tracing_enabled.Rd af856a45f45682ac6a8b175a796a963d *man/local_active_span.Rd 189a77fb6f222100496956848e84d61f *man/log.Rd 3d9a34515c5e218ccec4dfe94dae3820 *man/log_severity_levels.Rd b5244cbfcf788748027a19a0c24b82c6 *man/logger_provider_noop.Rd 5333249d266bdc06a6d3b671c99016d5 *man/meter_provider_noop.Rd 91980023b239bfff13d3bb0b57c9e74e *man/otel_counter.Rd 4ae4d7a0575ad515a4a3e0bca60b0a8c *man/otel_gauge.Rd d50a2c7fa83bd9e7d019534a169d24fd *man/otel_histogram.Rd 2ef5fac56daeba95394cf66464c7bb01 *man/otel_logger.Rd 24b085f6f6f456092e6b9e1893ae736b *man/otel_logger_provider.Rd fdcd0178456c0f2e6e5de98eeb40cfd7 *man/otel_meter.Rd 6c03dcf41726e22629c78a97251ba935 *man/otel_meter_provider.Rd 609c80b64383f2d527179e15d4ce1fbb *man/otel_span.Rd e8df97549134cb323c2bf719fd5349f8 *man/otel_span_context.Rd 6cf9151bdae7bbbd4ab639a90471133e *man/otel_tracer.Rd 15b7f40843d1ba4c5e20992b42a7c815 *man/otel_tracer_provider.Rd ce1bba1bf18c15544efefde956fabbba *man/otel_up_down_counter.Rd ce82165e820f17aa8dffd3604634dce8 *man/pack_http_context.Rd e13da5a15d6c46c5fc9bc1c8446187d1 *man/start_local_active_span.Rd 2d04383617500c943b7ab26cf4176e41 *man/start_span.Rd f9db90f7407f2b78eb3110f8c271877b *man/tracer_provider_noop.Rd 23a3def6abd0601dcf503d0f9160017c *man/tracing-constants.Rd 421fa517f0f33436a7de44f80d4ba6ff *man/up_down_counter_add.Rd d163e8b2030010796749f78bf74956f6 *man/with_active_span.Rd f3b9e6a09811a42b8544211ece299afe *man/zci.Rd 632d2ed23a76b6195eaf4ea31193f628 *tests/testthat.R f11e3bddf06a70be72665fa941dd2de5 *tests/testthat/_snaps/api.md 13ab3fa371575018b543cb5abbb12a44 *tests/testthat/_snaps/as-attributes.md 4da96aafc9a6a2e0be4b104c93ecef6f *tests/testthat/_snaps/checks.md cff5787396db013c93b706837a6c18b4 *tests/testthat/_snaps/cov/rtrace.md d2c58b737219acb1a1c26dba31d600bb *tests/testthat/_snaps/defaults.md 29865ea9483d065ab4e3a59acdf69631 *tests/testthat/_snaps/formatting.md d43efea3b3d6b6a02f36ffa4a6d5f1ce *tests/testthat/_snaps/nocov/rtrace.md c5af11312a87bd5cec18beb9da3c3307 *tests/testthat/_snaps/onload.md 1f3638fdf4e26e2329a294b9f3b3d3c4 *tests/testthat/_snaps/print.md 5888437b1a0c5276b6d821374d5e0ddb *tests/testthat/_snaps/rtrace.md d996e1221caab9df4f0953e2a8b309b5 *tests/testthat/_snaps/spelling.md 6695c5ee482ca810876a87dcb51d0350 *tests/testthat/_snaps/tracer-provider-noop.md cfa728d5879d64b414bfd63c3e8d2983 *tests/testthat/_snaps/utils.md dc6a27007bdfffced90726cec77bd72e *tests/testthat/fixtures/oteltest/DESCRIPTION 94b31122c5b3c7c0740020b4562d62db *tests/testthat/fixtures/oteltest/NAMESPACE a1e3a497dcdded964811a2b565e125db *tests/testthat/fixtures/oteltest/R/oteltest.R 4cdf3e5663a737e5fcf23ec9ef99ceb3 *tests/testthat/fixtures/oteltest/inst/runme.R 4b6fa2e0b7091620b9b9f6a34cac3c94 *tests/testthat/helper-mock.R ad935d2a1bcd7f953a163ddf42a9e6c5 *tests/testthat/helper.R a04c96505c5cdbb7013c57a1755f10f5 *tests/testthat/test-api-dev.R 21b83f9feabeab5fc7b8743d4b0461b2 *tests/testthat/test-api.R 21a79afd057949d0a291328bf178a19d *tests/testthat/test-as-attributes.R b3888915219407b1172942cf9cc177b1 *tests/testthat/test-checks.R 19de1ea4e42a88146fac7c77420630e3 *tests/testthat/test-defaults.R 401c522ed28369ff75628d12b5254317 *tests/testthat/test-formatting.R 3d38277c31621ba592a3781507c11c42 *tests/testthat/test-logger-provider-noop.R cd161b3e5d2f4557665914394801128a *tests/testthat/test-meter-provider-noop.R 88a562083534fd0df26d7df132021685 *tests/testthat/test-no-eval.R 2fe8ed801cabd44ca6f09672d0dc2f41 *tests/testthat/test-onload.R 131315ced597640e0e23c700f2a19d8a *tests/testthat/test-print.R 00baa940f3ecdb261f7c38e1b4f41996 *tests/testthat/test-rtrace.R 27e7a2f079932ed8aebc51c77f2133af *tests/testthat/test-spelling.R 0811553b94a6d8171956298e31637934 *tests/testthat/test-tracer-name.R 24d57b583b2bb08edccc09ce82d4b826 *tests/testthat/test-tracer-provider-noop.R 67b44bc0f43eb4e5608e45ed90842514 *tests/testthat/test-utils.R otel/.aspell/0000755000176200001440000000000015046400616012555 5ustar liggesusersotel/.aspell/defaults.R0000644000176200001440000000021315046400616014503 0ustar liggesusersRd_files <- vignettes <- R_files <- description <- list( encoding = "UTF-8", language = "en", dictionaries = c("en_stats", "otel") ) otel/.aspell/otel.rds0000644000176200001440000000014015046400616014225 0ustar liggesusersb```b`aed`b2H慤榖US2s2K`̎P& Y v 0a 7t$wotel/R/0000755000176200001440000000000015046474033011424 5ustar liggesusersotel/R/print.R0000644000176200001440000001341715040667026012711 0ustar liggesusersgeneric_print <- function(x, ...) { writeLines(format(x, ...)) invisible(x) } #' @export format.otel_tracer_provider <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("get_tracer" %in% names(x)) { " get_tracer(name, version, schema_url, attributes)" }, if ("flush" %in% names(x)) { " flush()" }, if ("get_spans" %in% names(x)) { " get_spans()" }, NULL ) } #' @export print.otel_tracer_provider <- generic_print #' @export format.otel_tracer <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("start_span" %in% names(x)) { " start_span(name, attributes, links, options)" }, if ("is_enabled" %in% names(x)) { " is_enabled()" }, if ("flush" %in% names(x)) { " flush()" }, NULL ) } #' @export print.otel_tracer <- generic_print #' @export format.otel_span <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), paste0("name: ", x$name), "methods:", if ("add_event" %in% names(x)) { " add_event(name, attributes, timestamp)" }, if ("end" %in% names(x)) { " end(options, status_code)" }, if ("get_context" %in% names(x)) { " get_context()" }, if ("is_recording" %in% names(x)) { " is_recording()" }, if ("record_exception" %in% names(x)) { " record_exception(error_condition, attributes, ...)" }, if ("set_attribute" %in% names(x)) { " set_attribute(name, value)" }, if ("set_status" %in% names(x)) { " set_status(status_code, description)" }, if ("update_name" %in% names(x)) { " update_name(name)" }, NULL ) } #' @export print.otel_span <- generic_print #' @export format.otel_span_context <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("get_span_id" %in% names(x)) { " get_span_id()" }, if ("get_trace_flags" %in% names(x)) { " get_trace_flags()" }, if ("get_trace_id" %in% names(x)) { " get_trace_id()" }, if ("is_remote" %in% names(x)) { " is_remote()" }, if ("is_sampled" %in% names(x)) { " is_sampled()" }, if ("is_valid" %in% names(x)) { " is_valid()" }, if ("to_http_headers" %in% names(x)) { " to_http_headers()" }, NULL ) } #' @export print.otel_span_context <- generic_print #' @export format.otel_logger_provider <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("get_logger" %in% names(x)) { " get_logger(name, minimum_severity, version, schema_url, attributes)" }, if ("flush" %in% names(x)) { " flush()" }, NULL ) } #' @export print.otel_logger_provider <- generic_print #' @export format.otel_logger <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("is_enabled" %in% names(x)) { " is_enabled()" }, if ("get_minimum_severity" %in% names(x)) { " get_minimum_severity()" }, if ("set_minimum_severity" %in% names(x)) { " set_minimum_severity(minimum_severity)" }, if ("log" %in% names(x)) { " log(msg, severity, span_context, attributes, ..., .envir)" }, if ("trace" %in% names(x)) { " trace(msg, span_context, attributes, ..., .envir)" }, if ("debug" %in% names(x)) { " debug(msg, span_context, attributes, ..., .envir)" }, if ("info" %in% names(x)) { " info(msg, span_context, attributes, ..., .envir)" }, if ("warn" %in% names(x)) { " warn(msg, span_context, attributes, ..., .envir)" }, if ("error" %in% names(x)) { " error(msg, span_context, attributes, ..., .envir)" }, if ("fatal" %in% names(x)) { " fatal(msg, span_context, attributes, ..., .envir)" }, NULL ) } #' @export print.otel_logger <- generic_print #' @export format.otel_meter_provider <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("get_meter" %in% names(x)) { " get_meter(name, version, schema_url, attributes)" }, if ("flush" %in% names(x)) { " flush(timeout)" }, if ("shutdown" %in% names(x)) { " shutdown(timeout)" }, if ("get_metrics" %in% names(x)) { " get_metrics()" }, NULL ) } #' @export print.otel_meter_provider <- generic_print #' @export format.otel_meter <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("create_counter" %in% names(x)) { " create_counter(name, description, unit)" }, if ("create_up_down_counter" %in% names(x)) { " create_up_down_counter(name, description, unit)" }, if ("create_histogram" %in% names(x)) { " create_histogram(name, description, unit)" }, if ("create_gauge" %in% names(x)) { " create_gauge(name, description, unit)" }, NULL ) } #' @export print.otel_meter <- generic_print #' @export format.otel_counter <- function(x, ...) { c( paste0("<", paste(class(x), collapse = "/"), ">"), "methods:", if ("add" %in% names(x)) { " add(value, attributes, span_context)" }, if ("record" %in% names(x)) { " record(value, attributes, span_context)" }, NULL ) } #' @export print.otel_counter <- generic_print #' @export format.otel_up_down_counter <- format.otel_counter #' @export print.otel_up_down_counter <- generic_print #' @export format.otel_histogram <- format.otel_counter #' @export print.otel_histogram <- generic_print #' @export format.otel_gauge <- format.otel_counter #' @export print.otel_gauge <- generic_print otel/R/constants.R0000644000176200001440000000360615040730461013562 0ustar liggesusers#' OpenTelemetry tracing constants #' #' Various constants related OpenTelemetry tracing. #' #' @details #' ## `invalid_trace_id` #' #' `invalid_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. #' #' @format NULL #' @name tracing-constants #' @export #' @family OpenTelemetry trace API #' @return Not applicable. #' @examples #' invalid_trace_id invalid_trace_id <- strrep("0", 32) #' @details #' ## `invalid_span_id` #' #' `invalid_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. #' #' @rdname tracing-constants #' @format NULL #' @export #' @examples #' invalid_span_id invalid_span_id <- strrep("0", 16) #' @details #' ## `span_kinds` #' #' `span_kinds` is a character vector listing all possible span kinds. #' See the [OpenTelemetry specification]( #' https://opentelemetry.io/docs/specs/otel/trace/api/#spankind) for #' when to use which. #' #' @rdname tracing-constants #' @format NULL #' @export #' @examples #' span_kinds span_kinds <- c( default = "internal", "server", "client", "producer", "consumer" ) #' @details #' ## `span_status_codes` #' #' `span_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. #' #' @rdname tracing-constants #' @format NULL #' @export #' @examples #' span_status_codes span_status_codes <- c(default = "unset", "ok", "error") otel/R/logger-provider-noop.R0000644000176200001440000002314115054313132015617 0ustar liggesusers#' OpenTelemetry Logger Provider Object #' #' @description #' [otel_logger_provider] -> [otel_logger] #' #' @details #' 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]. #' #' # Implementations #' #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `logger_provider$get_logger()` #' #' Get or create a new logger object. #' #' ### Usage #' #' ```r #' logger_provider$get_logger( #' name = NULL, #' version = NULL, #' schema_url = NULL, #' attributes = NULL #' ) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' An OpenTelemetry logger ([otel_logger]) object. #' #' ### See also #' #' [get_default_logger_provider()], [get_logger()]. #' # ------------------------------------------------------------------------- #' ## `logger_provider$flush()` #' #' Force any buffered logs to flush. Logger providers might not implement #' this method. #' #' ### Usage #' #' ```r #' logger_provider$flush() #' ``` #' #' ### Value #' #' Nothing. #' #' @name otel_logger_provider #' @family low level logs API #' @return Not applicable. #' @examples #' lp <- otel::get_default_logger_provider() #' lgr <- lp$get_logger() #' lgr$is_enabled() NULL #' No-op logger provider #' #' This is the logger provider ([otel_logger_provider]) otel uses when #' logging is disabled. #' #' All methods are no-ops or return objects that are also no-ops. #' #' @family low level logs API #' @usage NULL #' @format NULL #' @keywords internal #' @export #' @return Not applicable. #' @examples #' logger_provider_noop$new() logger_provider_noop <- list( new = function() { structure( list( get_logger = function( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL ) { logger_noop$new( name, minimum_severity = minimum_severity, version = version, schema_url = schema_url, attributes = attributes ) }, flush = function() { # noop } ), class = c( "otel_logger_provider_noop", "otel_logger_provider" ) ) } ) #' OpenTelemetry Logger Object #' @name otel_logger #' @family low level logs API #' @description #' [otel_logger_provider] -> [otel_logger] #' #' @details #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `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. #' #' ### Usage #' #' ```r #' logger$is_enabled(severity = "info", event_id = NULL) #' ``` #' #' ### Arguments #' #' - `severity`: Check if logs are emitted at this severity level. #' - `event_id`: Not implemented yet. #' #' ### Value #' #' Logical scalar. #' # ------------------------------------------------------------------------- #' ## `logger$get_minimum_severity()` #' #' Get the current minimum severity at which the logger is emitting logs. #' #' ### Usage #' #' ```r #' logger_get_minimum_severity() #' ``` #' #' ### Value #' #' Named integer scalar. #' # ------------------------------------------------------------------------- #' ## `logger$set_minimum_severiry()` #' #' Set the minimum severity for emitting logs. #' #' ### Usage #' #' ```r #' logger$set_minimum_severity(minimum_severity) #' ``` #' #' ### Arguments #' #' - `minimum_severity`: Log severity, a string, one of #' `r md_log_severity_levels`. #' #' ### Value #' #' Nothing. #' # ------------------------------------------------------------------------- #' ## `logger$log()` #' #' Log an OpenTelemetry log message. #' #' ### Usage #' #' ```r #' 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() #' ) #' ``` #' #' ### Arguments #' #' - `msg`: Log message, may contain R expressions to evaluate within #' braces. #' - `severity`: Log severity, a string, one of #' `r md_log_severity_levels`. #' - `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. #' #' ### Value #' #' 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"`. #' #' @return Not applicable. #' @examples #' lp <- get_default_logger_provider() #' lgr <- lp$get_logger() #' platform <- utils::sessionInfo()$platform #' lgr$log("This is a log message from {platform}.", severity = "trace") NULL logger_noop <- list( new = function( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL ) { self <- structure( list( trace = function(...) { invisible(self) }, debug = function(...) { invisible(self) }, info = function(...) { invisible(self) }, warn = function(...) { invisible(self) }, error = function(...) { invisible(self) }, fatal = function(...) { invisible(self) }, is_enabled = function(severity = "info", event_id = NULL) { FALSE }, get_minimum_severity = function() { c("maximumseverity" = 255L) }, set_minimum_severity = function(minimum_severity) { invisible(self) }, log = function( msg = "", severity = "info", span_context = NULL, ... ) { invisible(self) } ), class = c("otel_logger_noop", "otel_logger") ) self } ) # nocov start log_record_noop <- list( new = function() { self <- structure( list( set_timestamp = function(timestamp) { invisible(self) }, set_observed_timestamp = function(timestamp) { invisible(self) }, set_severity = function(severity) { invisible(self) }, set_body = function(message) { invisible(self) }, set_attribute = function(key, value) { invisible(self) }, set_event_id = function(id, name) { invisible(self) }, set_trace_id = function(trace_id) { invisible(self) }, set_span_id = function(span_id) { invisible(self) }, set_trace_flags = function(trace_flags) { invisible(self) } ), class = c("otel_log_record_noop", "otel_log_record") ) self } ) # nocov end otel/R/onload.R0000644000176200001440000000560215051651306013022 0ustar liggesusers# used by otelsdk otel_cache_vars <- c( "tracer_provider", "logger_provider", "meter_provider", "tracer_app", "instruments" ) # used by otelsdk otel_clean_cache <- function() { for (nm in otel_cache_vars) { the[[nm]] <- NULL } } # used by otelsdk otel_save_cache <- function() { copy <- new.env(parent = emptyenv()) for (nm in otel_cache_vars) { copy[[nm]] <- the[[nm]] } copy } # used by otelsdk otel_restore_cache <- function(copy) { for (nm in names(copy)) { the[[nm]] <- copy[[nm]] } } # nocov start the <- new.env(parent = emptyenv()) the$mode <- "prod" .onLoad <- function(libname, pkgname) { otel_clean_cache() setup_dev_env() setup_r_trace() } # nocov end setup_dev_env <- function(envir = asNamespace(.packageName)) { ev <- tolower(Sys.getenv("OTEL_ENV")) if (ev %in% c("dev", "devel", "development")) { the$mode <- "dev" assign( "start_local_active_span", start_local_active_span_dev, envir = envir ) assign( "start_span", start_span_dev, envir = envir ) assign( "end_span", end_span_dev, envir = envir ) assign( "get_default_tracer_provider", get_default_tracer_provider_dev, envir = envir ) assign("get_tracer", get_tracer_dev, envir = envir) assign( "get_default_logger_provider", get_default_logger_provider_dev, envir = envir ) assign("get_logger", get_logger_dev, envir = envir) assign( "get_default_meter_provider", get_default_meter_provider_dev, envir = envir ) assign("get_meter", get_meter_dev, envir = envir) assign("local_active_span", local_active_span_dev, envir = envir) assign("with_active_span", with_active_span_dev, envir = envir) assign( "get_active_span_context", get_active_span_context_dev, envir = envir ) assign( "get_active_span", get_active_span_dev, envir = envir ) assign( "extract_http_context", extract_http_context_dev, envir = envir ) assign( "pack_http_context", pack_http_context_dev, envir = envir ) } } setup_r_trace <- function() { ev <- trimws(Sys.getenv("OTEL_R_INSTRUMENT_PKGS", "")) if (ev == "") { return() } pkgs <- strsplit(ev, ",", fixed = TRUE)[[1]] for (pkg in pkgs) { PKG <- gsub(".", "_", toupper(pkg), fixed = TRUE) inc <- get_env(paste0("OTEL_R_INSTRUMENT_PKGS_", PKG, "_INCLUDE")) exc <- get_env(paste0("OTEL_R_INSTRUMENT_PKGS_", PKG, "_EXCLUDE")) if (!is.null(inc)) { inc <- trimws(strsplit(inc, ",")[[1]]) } if (!is.null(exc)) { exc <- trimws(strsplit(exc, ",")[[1]]) } if (pkg %in% loadedNamespaces()) { trace_namespace(pkg, inc, exc) } else { setHook( packageEvent(pkg, "onLoad"), function(...) trace_namespace(pkg, inc, exc) ) } } } otel/R/tracer-provider-noop.R0000644000176200001440000005007115054314752015633 0ustar liggesusers#' OpenTelemetry Tracer Provider Object #' #' @description #' [otel_tracer_provider] -> [otel_tracer] -> [otel_span] -> [otel_span_context] #' #' @details #' 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]. #' #' # Implementations #' #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `tracer_provider$get_tracer()` #' #' Get or create a new tracer object. #' #' ### Usage #' #' ```r #' tracer_provider$get_tracer( #' name = NULL, #' version = NULL, #' schema_url = NULL, #' attributes = NULL #' ) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' Returns an OpenTelemetry tracer ([otel_tracer]) object. #' #' ### See also #' #' [get_default_tracer_provider()], [get_tracer()]. #' # ------------------------------------------------------------------------- #' ## `tracer_provider$flush()` #' #' Force any buffered spans to flush. Tracer providers might not implement #' this method. #' #' ### Usage #' #' ``` #' tracer_provider$flush() #' ``` #' #' ### Value #' #' Nothing. #' #' @name otel_tracer_provider #' @return Not applicable. #' @family low level trace API #' @examples #' tp <- otel::get_default_tracer_provider() #' trc <- tp$get_tracer() #' trc$is_enabled() NULL #' No-op tracer provider #' #' 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. #' #' @family low level trace API #' @usage NULL #' @format NULL #' @export #' @return Not applicable. #' @examples #' tracer_provider_noop$new() tracer_provider_noop <- list( new = function() { self <- structure( list( get_tracer = function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) { tracer_noop$new(name, version, schema_url, attributes) }, flush = function() { # noop invisible(self) }, get_spans = function() { list() } ), class = c( "otel_tracer_provider_noop", "otel_tracer_provider" ) ) self } ) #' OpenTelemetry Tracer Object #' @name otel_tracer #' @family low level trace API #' @description #' [otel_tracer_provider] -> [otel_tracer] -> [otel_span] -> [otel_span_context] #' #' @details #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `tracer$start_span()` #' #' Creates and starts a new span. #' #' It does not activate the new span. #' #' It is equivalent to the [start_span()] function. #' #' ### Usage #' #' ```r #' tracer_start_span( #' name = NULL, #' attributes = NULL, #' links = NULL, #' options = NULL #' ) #' ``` #' #' ### Arguments #' #' - `name`: `r doc_arg()[["span-name"]]` #' - `attributes`: `r doc_arg()[["attributes"]]` #' - `links`: `r doc_arg()[["links"]]` #' - `options`: `r paste0(" ", doc_arg()[["span-options"]])` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' tracer$is_enabled() #' ``` #' #' ### Value #' #' Logical scalar. #' # ------------------------------------------------------------------------- #' ## `tracer$flush()` #' #' Flush the tracer provider: force any buffered spans to flush. Tracer #' providers might not implement this method. #' #' ### Usage #' #' ```r #' tracer$flush() #' ``` #' #' ### Value #' #' Nothing. #' #' @return Not applicable. #' @examples #' tp <- get_default_tracer_provider() #' trc <- tp$get_tracer() #' trc$is_enabled() NULL tracer_noop <- list( new = function(name = NULL, attributes = NULL, links = NULL, options = NULL) { self <- structure( list( start_span = function( name = NULL, attributes = NULL, links = NULL, options = NULL ) { span_noop$new( name = name, attributes = attributes, links = links, options = options ) }, get_active_span_context = function() span_context_noop$new(), get_active_span = function() span_noop$new(), is_enabled = function() FALSE, flush = function() { invisible(self) }, extract_http_context = function(headers) { span_context_noop$new() } ), class = c("otel_tracer_noop", "otel_tracer") ) self } ) #' OpenTelemetry Span Object #' #' @name otel_span #' @family low level trace API #' @description #' [otel_tracer_provider] -> [otel_tracer] -> [otel_span] -> [otel_span_context] #' #' @details #' 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.) #' #' # Lifetime #' #' 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()]. #' #' # Activation #' #' 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. #' #' ## Automatic spans #' #' [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. #' #' ## Manual spans #' #' [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()].) #' #' # Parent spans #' #' 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. #' #' # Methods # we cannot document these inline, because then roxygen2 adds the 'span_noop' # alias to the manual page. # ------------------------------------------------------------------------- #' ## `span$add_event()` #' #' Add a single event to the span. #' #' ### Usage #' #' ```r #' span$add_event(name, attributes = NULL, timestamp = NULL) #' ``` #' #' ### Arguments #' #' * `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. #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$end(options = NULL, status_code = NULL) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$get_context() #' ``` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$is_recording() #' ``` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$record_exception(error_condition, attributes, ...) #' ``` #' #' ### Arguments #' #' - `error_condition`: An R error object to record. #' - `attributes`: Additional attributes to add to the exception event. #' - `...`: Passed to the `span$add_event()` method. #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$set_attribute(name, value) #' ``` #' #' ### Arguments #' #' * `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. #' #' ### 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. #' #' ### Usage #' #' ```r #' span$set_status(status_code, description = NULL) #' ``` #' #' ### Arguments #' #' * `status_code`: Possible values: #' `r paste(span_status_codes, collapse = ", ")`. #' * `description`: Optional description, a string. #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span$update_name(name) #' ``` #' #' ### Arguments #' #' - `name`: String, the new span name. #' #' ### Value #' #' The span object itself, invisibly. #' #' @return Not applicable. #' @examples #' 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() NULL span_noop <- list( new = function(name = "", ...) { self <- structure( list( get_context = function() { span_context_noop$new() }, # We don't need this currently, because we never return an invalid # span, `get_active_span_context()` returns an invalid span context, # but we don't have a `get_active_span()` function. is_valid = function() { FALSE }, is_recording = function() { FALSE }, set_attribute = function(name, value = NULL) { invisible(self) }, add_event = function(name, attributes = NULL, timestamp = NULL) { invisible(self) }, add_link = function(target, attributes = NULL) { invisible(self) }, set_status = function( status_code = c("unset", "ok", "error"), description = NULL ) { invisible(self) }, update_name = function(name) { invisible(self) }, end = function(options = NULL, status_code = NULL) { invisible(self) }, record_exception = function(attributes = NULL) { invisible(self) }, activate = function(activation_scope, end_on_exit = FALSE) { invisible(self) }, deactivate = function(activation_scope) { invisible(self) } ), class = c("otel_span_noop", "otel_span") ) self$name <- name %||% "" self } ) #' An OpenTelemetry Span Context object #' #' @description #' [otel_tracer_provider] -> [otel_tracer] -> [otel_span] -> [otel_span_context] #' #' @details #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `span_context$get_span_id()` #' #' Get the id of the span. #' #' ### Usage #' #' ```r #' span_context$get_span_id() #' ``` #' #' ### Value #' #' 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](https://w3c.github.io/trace-context/#trace-flags) #' for more details on trace flags. #' #' ### Usage #' #' ```r #' span_context$get_trace_flags() #' ``` #' #' ### Value #' #' 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](https://w3c.github.io/trace-context/#sampled-flag). #' * `is_random`: logical flag, it specifies how trace ids are generated. #' See details in the [specification]( #' https://w3c.github.io/trace-context/#random-trace-id-flag). #' # ------------------------------------------------------------------------- #' ## `span_context$get_trace_id()` #' #' Get the id of the trace the span belongs to. #' #' ### Usage #' #' ```r #' span_context$get_trace_id() #' ``` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span_context$is_remote() #' ``` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span_context$is_sampled() #' ``` #' #' ### Value #' #' 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]. #' #' ### Usage #' #' ```r #' span_context$is_valid() #' ``` #' #' ### Value #' #' 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. #' #' ### Usage #' #' ```r #' span_context$to_http_headers() #' ``` #' #' ### Value #' #' A named character vector, the HTTP header representation of the span #' context. Usually includes a `traceparent` header. May include other #' headers. #' #' @name otel_span_context #' @family low level trace API #' @return Not applicable. #' @examples #' 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() NULL span_context_noop <- list( new = function(...) { self <- structure( list( is_valid = function() { FALSE }, get_trace_flags = function() { list() }, get_trace_id = function() { invalid_trace_id }, get_span_id = function() { invalid_span_id }, is_remote = function() { FALSE }, is_sampled = function() { FALSE }, to_http_headers = function() { structure(character(), names = character()) } ), class = c("otel_span_context_noop", "otel_span_context") ) self } ) otel/R/as-attributes.R0000644000176200001440000000537315042430227014337 0ustar liggesusers#' R objects as OpenTelemetry attributes #' #' Convert a list of R objects to a form that is suitable as OpenTelemetry #' attributes. #' #' @param x A list of R objects, to be used as OpenTelemetry attributes. #' @return 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 (`r paste0(otel_attr_types, collapse = ", ")`), then #' their printed form is captured using [utils::capture.output()]. #' #' ## Limits #' #' The number of attributes can be limited with the #' `r otel_attr_cnt_limit_var` environment variable. The default is #' `r otel_attr_cnt_limit_dflt`. #' #' The length of the each attribute (vector) can be limited with the #' `r otel_attr_val_lth_limit_var` environment variable. The default is #' ``r format(otel_attr_val_lth_limit_dflt)``. 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. #' #' @export #' @eval paste("@aliases", otel_attr_cnt_limit_var, otel_attr_val_lth_limit_var) #' @examples #' as_attributes(list( #' number = 1.0, #' vector = 1:10, #' string = "otel", #' string_vector = letters, #' object = mtcars #' )) as_attributes <- function(x) { if (!is.list(x)) { stop("Invalid argument: `x` must be a list in `as_attributes()`.") } len_limit <- get_env_count(otel_attr_cnt_limit_var, otel_attr_cnt_limit_dflt) val_len_limit <- get_env_count( otel_attr_val_lth_limit_var, otel_attr_val_lth_limit_dflt ) if (length(x) > len_limit) { x <- x[seq_len(len_limit)] } # create unique names for the attributes nms <- as.character(names(x)) length(nms) <- length(x) if (anyNA(nms) || any(nms == "")) { bad <- is.na(nms) | nms == "" nms[bad] <- as.character(seq_along(x))[bad] } nms <- make.unique(nms) for (i in seq_along(x)) { if (!typeof(x[[i]]) %in% otel_attr_types) { x[[i]] <- utils::capture.output(print(x[[i]])) } if (length(x[[i]]) > val_len_limit) { length(x[[i]]) <- val_len_limit } if (is.double(x[[i]]) && !all(is.finite(x[[i]]))) { # as.character keeps NAs, which is not what we want here x[[i]] <- paste(x[[i]]) } } structure(x, names = nms) } otel_attr_cnt_limit_var <- "OTEL_ATTRIBUTE_COUNT_LIMIT" otel_attr_cnt_limit_dflt <- 128L otel_attr_val_lth_limit_var <- "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT" otel_attr_val_lth_limit_dflt <- Inf otel_attr_types <- c(typeof(""), typeof(TRUE), typeof(1), typeof(1L)) otel/R/tracer-name.R0000644000176200001440000001212715051542676013755 0ustar liggesusers#' Default tracer name (and meter and logger name) for an R package #' #' 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. #' #' ## About tracer names #' #' 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. #' #' ## Setting the tracer name #' #' 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. #' #' ## Automatic tracer name detection in otel #' #' 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.` as the tracer name. #' `` is usually the package name. #' #' ## Choosing a tracer name #' #' The [OpenTelemetry specification]( #' https://opentelemetry.io/docs/specs/otel/trace/api/#get-a-tracer #' ) 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.` as the tracer name. #' #' #' @param name Custom tracer name. If `NULL` then otel will construct a #' a tracer (meter, logger) name according to the algorithm detailed #' below. #' #' @return 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. #' #' @aliases otel_tracer_name #' @export #' @examples #' default_tracer_name() default_tracer_name <- function(name = NULL) { if (!is.null(name)) { ret <- list(name = name, package = NA_character_) ret[["on"]] <- is_scope_on(ret) return(ret) } for (n in 1:sys.nframe()) { top <- topenv(parent.frame(n), NULL) topname <- environmentName(top) if (topname == "" || topname == "otel" || topname == "otelsdk") { # keep going } else if (topname == "base" || topname == "R_GlobalEnv") { nm <- get0("otel_tracer_name", .GlobalEnv, inherits = FALSE) %||% "org.r-project.R" ret <- list(name = nm, package = "R") ret[["on"]] <- is_scope_on(ret) return(ret) } else { nm <- get0("otel_tracer_name", top, inherits = FALSE) %||% paste0("r.package.", topname) ret <- list(name = nm, package = topname) ret[["on"]] <- is_scope_on(ret) return(ret) } } ret <- list(name = "org.r-project.R", package = "R") ret[["on"]] <- is_scope_on(ret) ret } otel_emit_scopes_envvar <- "OTEL_R_EMIT_SCOPES" otel_suppress_scopes_envvar <- "OTEL_R_SUPPRESS_SCOPES" is_scope_on <- function(scope) { inc <- get_env(otel_emit_scopes_envvar) exc <- get_env(otel_suppress_scopes_envvar) # shortcut for most common case if (is.null(inc) && is.null(exc)) { return(TRUE) } if (!is.null(inc)) { inc <- trimws(strsplit(inc, ",")[[1]]) } if (!is.null(exc)) { exc <- trimws(strsplit(exc, ",")[[1]]) } flt <- glob_filter(c(scope$name, scope$package), inc, exc) length(flt) > 0 } otel/R/rtrace.R0000644000176200001440000000172715044444711013034 0ustar liggesuserstrace_namespace <- function(pkg, include = NULL, exclude = NULL) { msg("Instrumenting {.pkg {pkg}}.") ns <- asNamespace(pkg) trace_env(ns, name = pkg, include = include, exclude = exclude) } trace_env <- function( env, name = NULL, include = NULL, exclude = NULL ) { nms <- glob_filter(ls(env), include, exclude) lapply(nms, function(nm) { obj <- get(nm, envir = env) if (!is.function(obj)) { return() } span_name <- paste0(name, "::", nm) suppressMessages(trace( nm, tracer = substitute( { # nocov start .__span <- otel::start_span(sn, tracer = "org.r-lib.otel") .__scope <- .__span$activate(NULL) # nocov end }, list(sn = span_name) ), exit = quote({ # nocov start try(.__span$deactivate(.__scope)) try(.__span$end()) # nocov end }), print = FALSE, where = env )) NULL }) invisible() } otel/R/utils.R0000644000176200001440000000312315044620776012713 0ustar liggesusers`%||%` <- function(l, r) if (is.null(l)) r else l errmsg <- function(..., class = "otel_error_message") { cnd <- structure( list(message = paste0(c(..., "\n"), collapse = "")), class = c(class, "message", "condition") ) message(cnd) } msg <- function(message, .envir = parent.frame()) { if ("cli" %in% loadedNamespaces()) { cli::cli_alert_info(message, .envir = .envir) } } get_env <- function(n) { v <- Sys.getenv(n) if (v != "") v else NULL } glob_filter <- function(x, include = NULL, exclude = NULL) { if (is.null(include)) { res <- x } else { res <- character() for (pat in include) { res <- c(res, grep(utils::glob2rx(pat), x, value = TRUE)) } res <- unique(res) } for (pat in exclude) { res <- setdiff( res, grep(utils::glob2rx(pat), res, value = TRUE) ) } res } get_env_count <- function(var, default) { strval <- Sys.getenv(var) if (tolower(strval) == "inf") { return(Inf) } intval <- suppressWarnings(as.integer(strval)) if (!is.na(intval) && intval >= 0) { return(intval) } if (default == Inf) { return(Inf) } intval <- suppressWarnings(as.integer(default)) if (!is.na(intval) && intval >= 0) { return(intval) } stop( "Invalid `default` in `get_env_count()`, must be a non-negative ", "integer scalar." ) } map_lgl <- function(.x, .f, ...) { vapply(.x, .f, logical(1), ...) } map_chr <- function(.x, .f, ...) { vapply(.x, .f, character(1), ...) } mkdirp <- function(dir) { s <- map_lgl(dir, dir.create, recursive = TRUE, showWarnings = FALSE) invisible(s) } otel/R/api.R0000644000176200001440000010350015053315002012303 0ustar liggesusers #' Get a tracer from the default tracer provider #' #' Calls [get_default_tracer_provider()] to get the default tracer #' provider. Then calls its `$get_tracer()` method to create a new tracer. #' #' 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. #' #' @param name Name of the new tracer. If missing, then deduced #' automatically using [default_tracer_name()]. Make sure you read #' the manual page of [default_tracer_name()] before using this argument. #' @param 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"`. #' @param schema_url Optional. Specifies the Schema URL that should be #' recorded in the emitted telemetry. #' @param attributes Optional. Specifies the instrumentation scope #' attributes to associate with emitted telemetry. #' @param ... Additional arguments are passed to the `get_tracer()` #' method of the provider. #' @param provider Tracer provider to use. If `NULL`, then it uses #' [get_default_tracer_provider()] to get a tracer provider. #' #' @return An OpenTelemetry tracer, an [otel_tracer] object. #' #' @export #' @family low level trace API #' @examples #' 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() # safe start get_tracer <- function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { tryCatch({ # safe # does setup if necessary provider <- provider %||% get_default_tracer_provider() trc <- provider$get_tracer(name, version, schema_url, attributes, ...) invisible(trc) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe tracer_noop$new() # safe }) # safe } # safe end get_tracer_safe <- get_tracer #' Get a logger from the default logger provider #' #' @param name Name of the new tracer. If missing, then deduced automatically. #' @param minimum_severity A log level, the minimum severity log messages #' to log. See [log_severity_levels]. #' @param ... Additional arguments are passed to the `get_logger()` #' method of the provider. #' @param provider Tracer provider to use. If `NULL`, then it uses #' [get_default_tracer_provider()] to get a tracer provider. #' @inheritParams get_tracer #' #' @return An [otel_logger] object. #' #' @export #' @family low level logs API #' @examples #' myfun <- function() { #' lgr <- otel::get_logger() #' otel::log("Log message", logger = lgr) #' } #' myfun() # safe start get_logger <- function( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { tryCatch({ # safe # does setup if necessary provider <- provider %||% get_default_logger_provider() lgr <- provider$get_logger( name, minimum_severity, version, schema_url, attributes, ... ) invisible(lgr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end get_logger_safe <- get_logger #' Get a meter from the default meter provider #' #' @param name Name of the new tracer. If missing, then deduced automatically. #' @param ... Additional arguments are passed to the `get_meter()` #' method of the provider. #' @param provider Meter provider to use. If `NULL`, then it uses #' [get_default_meter_provider()] to get a tracer provider. #' #' @return An [otel_meter] object. #' #' @inheritParams get_tracer #' @export #' @family low level metrics API #' @examples #' myfun <- function() { #' mtr <- otel::get_meter() #' ctr <- mtr$create_counter("session-count") #' ctr$add(1) #' } #' myfun() # safe start get_meter <- function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { tryCatch({ # safe # does setup if necessary provider <- provider %||% get_default_meter_provider() mtr <- provider$get_meter(name, version, schema_url, attributes, ...) invisible(mtr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe meter_noop$new() # safe }) # safe } # safe end get_meter_safe <- get_meter #' Activate an OpenTelemetry span for an R scope #' #' @description #' 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. #' #' @details #' 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. #' #' @param span The OpenTelemetry span to activate. #' @param end_on_exit Whether to end the span when exiting the activation #' scope. #' @param activation_scope The scope to activate the span for, defaults to #' the caller frame. #' @return Nothing. #' #' @export #' @family OpenTelemetry trace API #' @family tracing for concurrent code #' @inherit start_span examples # safe start local_active_span <- function( span, end_on_exit = FALSE, activation_scope = parent.frame() ) { tryCatch({ # safe invisible(span$activate(activation_scope, end_on_exit = end_on_exit)) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe }) # safe } # safe end local_active_span_safe <- local_active_span #' Evaluate R code with an active OpenTelemetry span #' #' @description #' 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. #' #' @details #' 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. #' #' @param span The OpenTelemetry span to activate. #' @param expr R expression to evaluate. #' @param end_on_exit Whether to end after evaluating the R expression. #' @return The return value of `expr`. #' #' @export #' @family OpenTelemetry trace API #' @family tracing for concurrent code #' @examples #' 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() # safe start with_active_span <- function(span, expr, end_on_exit = FALSE) { local({ tryCatch({ # safe invisible(span$activate(end_on_exit = end_on_exit)) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe }) # safe expr }) } # safe end with_active_span_safe <- with_active_span #' OpenTelemetry log severity levels #' #' 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. #' #' @export #' @usage NULL #' @format NULL #' @family OpenTelemetry logs API #' @return Not applicable. #' @examples #' log_severity_levels log_severity_levels <- c( "trace" = 1L, "trace2" = 2L, "trace3" = 3L, "trace4" = 4L, "debug" = 5L, "debug2" = 6L, "debug3" = 7L, "debug4" = 8L, "info" = 9L, "info2" = 10L, "info3" = 11L, "info4" = 12L, "warn" = 13L, "warn2" = 14L, "warn3" = 15L, "warn4" = 16L, "error" = 17L, "error2" = 18L, "error3" = 19L, "error4" = 20L, "fatal" = 21L, "fatal2" = 22L, "fatal3" = 23L, "fatal4" = 24L, NULL ) md_log_severity_levels <- paste0( "\"", names(log_severity_levels), "\"", collapse = ", " ) #' Returns the active span, if any #' #' This is sometimes useful, to add additional attributes or links to the #' currently active span. #' #' @return The active span, an [otel_span] object, if any, or an invalid #' span if there is no active span. #' @export #' @examples #' fun <- function() { #' otel::start_local_active_span("fun") #' spn <- otel::get_active_span() #' spn$set_attribute("key", "attribute-value") #' } #' fun() # safe start get_active_span <- function() { tryCatch({ # safe trc <- get_tracer() trc$get_active_span() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe span_noop$new(NA_character_) # safe }) # safe } # safe end #' Returns the active span context #' #' This is sometimes useful for logs or metrics, to associate #' logging and metrics reporting with traces. #' #' Note that logs and metrics instruments automatically use the current #' span context, so often you don't need to call this function explicitly. #' #' @return 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`. #' #' @export #' @examples #' fun <- function() { #' otel::start_local_active_span("fun") #' fun2() #' } #' fun2 <- function() { #' otel::log("Log message", span_context = otel::get_active_span_context()) #' } #' fun() # safe start get_active_span_context <- function() { tryCatch({ # safe trc <- get_tracer() trc$get_active_span_context() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe span_context_noop$new(NA_character_) # safe }) # safe } # safe end get_active_span_context_safe <- get_active_span_context #' Pack the currently active span context into standard HTTP OpenTelemetry #' headers #' #' The returned headers can be sent over HTTP, or set as environment #' variables for subprocesses. #' #' @return A named character vector, with lowercase names. It might be an #' empty vector, e.g. if tracing is disabled. #' #' @export #' @seealso [extract_http_context()] #' @examples #' hdr <- otel::pack_http_context() #' ctx <- otel::extract_http_context() #' ctx$is_valid() # safe start pack_http_context <- function() { tryCatch({ # safe trc <- get_tracer() trc$get_active_span_context()$to_http_headers() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe structure(character(), names = character()) # safe }) # safe } # safe end pack_http_context_safe <- pack_http_context #' Extract a span context from HTTP headers received from a client #' #' The return value can be used as the `parent` option when starting #' a span. #' #' @param headers A named list with one or two strings: `traceparent` is #' mandatory, and `tracestate` is optional. #' #' @return And [otel_span_context] object. #' #' @export #' @seealso [pack_http_context()] #' @inherit pack_http_context examples # safe start extract_http_context <- function(headers) { tryCatch({ # safe trc <- get_tracer() trc$extract_http_context(headers) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe span_context_noop$new(NA_character_) # safe }) # safe } # safe end extract_http_context_safe <- extract_http_context #' Start an OpenTelemetry span. #' #' @description #' 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. #' #' @details #' 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. #' #' @param name `r doc_arg()[["span-name"]]` #' @param attributes `r doc_arg()[["attributes"]]` #' @param links `r doc_arg()[["links"]]` #' @param options `r doc_arg()[["span-options"]]` #' @param ... Additional arguments are passed to the `start_span()` method #' of the tracer. #' @param tracer A tracer object or the name of the tracer to use, see #' [get_tracer()]. If `NULL` then [default_tracer_name()] is used. #' #' @return An OpenTelemetry span ([otel_span]). #' #' @family OpenTelemetry trace API #' @export #' @examples #' 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() # safe start start_span <- function( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL ) { tryCatch({ # safe if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } invisible(tracer$start_span(name, attributes, links, options, ...)) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe span_noop$new() # safe }) # safe } # safe end start_span_safe <- start_span #' End an OpenTelemetry 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()]. #' #' #' @param span The span to end. #' @return Nothing. #' #' @inherit start_span examples #' @family OpenTelemetry trace API #' #' @export # safe start end_span <- function(span) { tryCatch({ # safe identity(NULL) span$end() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe invisible(NULL) # safe }) # safe } # safe end end_span_safe <- end_span #' Start and activate a span #' #' @description #' Creates, starts and activates an OpenTelemetry span. #' #' Usually you want this functions instead of [start_span()], which does #' not activate the new span. #' #' @details #' If `end_on_exit` is `TRUE` (the default), then it also ends the span #' when the activation scope finishes. #' #' @param activation_scope The R scope to activate the span for. Defaults #' to the caller frame. #' @param end_on_exit Whether to also end the span when the activation scope #' exits. #' @inheritParams start_span #' #' @return The new OpenTelemetry span object (of class [otel_span]), #' invisibly. See [otel_span] for information about the returned object. #' #' @family OpenTelemetry trace API #' @export #' @examples #' fn1 <- function() { #' otel::start_local_active_span("fn1") #' fn2() #' } #' fn2 <- function() { #' otel::start_local_active_span("fn2") #' } #' fn1() # safe start start_local_active_span <- function( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL, activation_scope = parent.frame(), end_on_exit = TRUE ) { tryCatch({ # safe if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } span <- tracer$start_span(name, attributes, links, options, ...) span$activate( activation_scope = activation_scope, end_on_exit = end_on_exit) invisible(span) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe span_noop$new() # safe }) # safe } # safe end start_local_active_span_safe <- start_local_active_span #' Check if tracing is active #' #' Checks whether OpenTelemetry tracing is active. This can be useful #' to avoid unnecessary computation when tracing is inactive. #' #' It calls [get_tracer()] with `name` and then it calls the tracer's #' `$is_enabled()` method. #' #' @param tracer Tracer object ([otel_tracer]). It can also be a tracer #' name, the instrumentation scope, or `NULL` for determining the tracer #' name automatically. Passed to [get_tracer()] if not a tracer object. #' @return `TRUE` is OpenTelemetry tracing is active, `FALSE` otherwise. #' #' @export #' @family OpenTelemetry trace API #' @examples #' fun <- function() { #' if (otel::is_tracing_enabled()) { #' xattr <- calculate_some_extra_attributes() #' otel::start_local_active_span("fun", attributes = xattr) #' } #' # ... #' } # safe start is_tracing_enabled <- function(tracer = NULL) { tryCatch({ # safe if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } tracer$is_enabled() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe FALSE # safe }) # safe } # safe end is_tracing_enabled_safe <- is_tracing_enabled #' Check whether OpenTelemetry logging is active #' #' This is useful for avoiding computation when logging is inactive. #' #' It calls [get_logger()] with `name` and then it calls the logger's #' `$is_enabled()` method. #' #' @param severity Check if logs are emitted at this severity level. #' @param logger Logger object ([otel_logger]), or a logger name, the #' instrumentation scope, to pass to [get_logger()]. #' @return `TRUE` is OpenTelemetry logging is active, `FALSE` otherwise. #' #' @export #' @family OpenTelemetry logs API #' @examples #' fun <- function() { #' if (otel::is_logging_enabled()) { #' xattr <- calculate_some_extra_attributes() #' otel::log("Starting fun", attributes = xattr) #' } #' # ... #' } # safe start is_logging_enabled <- function(severity = "info", logger = NULL) { tryCatch({ # safe if (!inherits(logger, "otel_tracer")) { logger <- get_logger(logger) } logger$is_enabled(severity) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe FALSE # safe }) # safe } # safe end is_logging_enabled_safe <- is_logging_enabled #' Check whether OpenTelemetry metrics collection is active #' #' This is useful for avoiding computation when metrics collection is inactive. #' #' It calls [get_meter()] with `name` and then it calls the meter's #' `$is_enabled()` method. #' #' @param meter Meter object ([otel_meter]), or a meter name, the #' instrumentation scope, to pass to [get_meter()]. #' @return `TRUE` is OpenTelemetry metrics collection is active, #' `FALSE` otherwise. #' #' @export #' @family OpenTelemetry metrics API #' @examples #' fun <- function() { #' if (otel::is_measuring_enabled()) { #' xattr <- calculate_some_extra_attributes() #' otel::counter_add("sessions", 1, attributes = xattr) #' } #' # ... #' } # safe start is_measuring_enabled <- function(meter = NULL) { tryCatch({ # safe if (!inherits(meter, "otel_meter")) { meter <- get_meter(meter) } meter$is_enabled() }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe FALSE # safe }) # safe } # safe end is_measuring_enabled_safe <- is_measuring_enabled #' Log an OpenTelemetry log message #' #' @param msg Log message. #' @param severity Log severity, a string, one of #' `r md_log_severity_levels`. #' @param ... Additional arguments are passed to the `$log()` method of #' the logger. #' @param logger Logger to use. If not an OpenTelemetry logger object #' ([otel_logger]), then it passed to [get_logger()] to get a logger. #' @return The logger, invisibly. #' #' @export #' @family OpenTelemetry logs API #' @examples #' host <- "my.db.host" #' port <- 6667 #' otel::log("Connecting to database at {host}:{port}") # safe start log <- function( msg, ..., severity = "info", logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, severity, ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_safe <- log #' @details `log_trace()` is the same as `log()` with `severity_level` #' "trace". #' @rdname log #' @export # safe start log_trace <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "trace", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_trace_safe <- log_trace #' @details `log_debug()` is the same as `log()` with `severity_level` #' "debug". #' @rdname log #' @export # safe start log_debug <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "debug", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_debug_safe <- log_debug #' @details `log_info()` is the same as `log()` with `severity_level` #' "info". #' @rdname log #' @export # safe start log_info <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "info", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_info_safe <- log_info #' @details `log_warn()` is the same as `log()` with `severity_level` #' "warn". #' @rdname log #' @export # safe start log_warn <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "warn", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_warn_safe <- log_warn #' @details `log_error)` is the same as `log()` with `severity_level` #' "error". #' @rdname log #' @export # safe start log_error <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "error", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_error_safe <- log_error #' @details `log_fatal()` is the same as `log()` with `severity_level` #' "fatal". #' @rdname log #' @export # safe start log_fatal <- function( msg, ..., logger = NULL ) { tryCatch({ # safe if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "fatal", ...) invisible(logger) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_noop$new() # safe }) # safe } # safe end log_fatal_safe <- log_fatal #' Increase an OpenTelemetry counter #' #' @param name Name of the counter. #' @param value Value to add to the counter, defaults to 1. #' @param attributes Additional attributes to add. #' @param context Span context. If missing the active context is used, #' if any. #' @param meter Meter object ([otel_meter]). Otherwise it is passed to #' [get_meter()] to get a meter. #' #' @return The counter object ([otel_counter]), invisibly. #' #' @family OpenTelemetry metrics instruments #' @family OpenTelemetry metrics API #' @export #' @examples #' otel::counter_add("total-session-count", 1) # safe start counter_add <- function( name, value = 1L, attributes = NULL, context = NULL, meter = NULL ) { tryCatch({ # safe if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_counter(name) ctr$add(value, attributes, context) invisible(ctr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe counter_noop$new() # safe }) # safe } # safe end counter_add_safe <- counter_add #' Increase or decrease an OpenTelemetry up-down counter #' #' @param name Name of the up-down counter. #' @param value Value to add to or subtract from the counter, defaults #' to 1. #' @param attributes Additional attributes to add. #' @param context Span context. If missing the active context is used, #' if any. #' @param meter Meter object ([otel_meter]). Otherwise it is passed to #' [get_meter()] to get a meter. #' #' @return The up-down counter object ([otel_up_down_counter]), invisibly. #' #' @family OpenTelemetry metrics instruments #' @family OpenTelemetry metrics API #' @export #' @examples #' otel::up_down_counter_add("session-count", 1) # safe start up_down_counter_add <- function( name, value = 1L, attributes = NULL, context = NULL, meter = NULL ) { tryCatch({ # safe if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_up_down_counter(name) ctr$add(value, attributes, context) invisible(ctr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe up_down_counter_noop$new() # safe }) # safe } # safe end up_down_counter_add_safe <- up_down_counter_add #' Record a value of an OpenTelemetry histogram #' #' @param name Name of the histogram. #' @param value Value to record. #' @param attributes Additional attributes to add. #' @param context Span context. If missing the active context is used, #' if any. #' @param meter Meter object ([otel_meter]). Otherwise it is passed to #' [get_meter()] to get a meter. #' #' @return The histogram object ([otel_histogram]), invisibly. #' #' @export #' @family OpenTelemetry metrics instruments #' @family OpenTelemetry metrics API #' @examples #' otel::histogram_record("response-time", 0.2) # safe start histogram_record <- function( name, value, attributes = NULL, context = NULL, meter = NULL ) { tryCatch({ # safe if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_histogram(name) ctr$record(value, attributes, context) invisible(ctr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe histogram_noop$new() # safe }) # safe } # safe end histogram_record_safe <- histogram_record #' Record a value of an OpenTelemetry gauge #' #' @param name Name of the gauge #' @param value Value to record. #' @param attributes Additional attributes to add. #' @param context Span context. If missing the active context is used, #' if any. #' @param meter Meter object ([otel_meter]). Otherwise it is passed to #' [get_meter()] to get a meter. #' #' @return The gauge object ([otel_gauge]), invisibly. #' #' @export #' @family OpenTelemetry metrics instruments #' @family OpenTelemetry metrics API #' @examples #' otel::gauge_record("temperature", 27) # safe start gauge_record <- function( name, value, attributes = NULL, context = NULL, meter = NULL ) { tryCatch({ # safe if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_gauge(name) ctr$record(value, attributes, context) invisible(ctr) }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe gauge_noop$new() # safe }) # safe } # safe end gauge_record_safe <- gauge_record otel/R/defaults.R0000644000176200001440000003405315042426067013363 0ustar liggesusers# To ensure consistent naming across projects, this specification # recommends that language specific environment variables are formed using # the following convention: # ``` # OTEL_{LANGUAGE}_{FEATURE} # ``` # https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#language-specific-environment-variables default_traces_exporter_envvar <- "OTEL_TRACES_EXPORTER" default_traces_exporter_envvar_r <- "OTEL_R_TRACES_EXPORTER" default_logs_exporter_envvar <- "OTEL_LOGS_EXPORTER" default_logs_exporter_envvar_r <- "OTEL_R_LOGS_EXPORTER" default_metrics_exporter_envvar <- "OTEL_METRICS_EXPORTER" default_metrics_exporter_envvar_r <- "OTEL_R_METRICS_EXPORTER" #' Get the default tracer 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. #' #' If there is no default set currently, then it creates and sets a #' default. #' #' The default tracer provider is created based on the #' `r default_traces_exporter_envvar_r` environment variable. This #' environment variable is specifically for R applications with #' OpenTelemetry support. #' #' If this is not set, then the generic `r default_traces_exporter_envvar` #' environment variable is used. This applies to all applications that #' support OpenTelemetry and use the OpenTelemetry SDK. #' #' @return The default tracer provider, an [otel_tracer_provider] #' object. See [otel_tracer_provider] for its methods. #' #' @family low level trace API #' @examples #' get_default_tracer_provider() #' @export # safe start get_default_tracer_provider <- function() { tryCatch({ # safe if (is.null(the$tracer_provider)) { setup_default_tracer_provider() } the$tracer_provider }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe tracer_provider_noop$new() # safe }) # safe } # safe end set_default_service_name <- function() { if (Sys.getenv("OTEL_SERVICE_NAME") == "") { Sys.setenv("OTEL_SERVICE_NAME" = "R") } } get_default_tracer_provider_safe <- get_default_tracer_provider #' @rdname get_default_tracer_provider #' @usage NULL #' @details #' The following values are allowed: setup_default_tracer_provider <- function() { evar <- default_traces_exporter_envvar_r ev <- Sys.getenv(evar, NA_character_) if (is.na(ev)) { evar <- default_traces_exporter_envvar ev <- Sys.getenv(evar, NA_character_) } tp <- if (is.na(ev)) { tracer_provider_noop$new() } else if (!grepl("::", ev)) { set_default_service_name() switch( ev, #' - `none`: no traces are exported. "none" = { tracer_provider_noop$new() }, #' - `stdout` or `console`: uses [otelsdk::tracer_provider_stdstream], #' to write traces to the standard output. "console" = , "stdout" = { otelsdk::tracer_provider_stdstream$new(list(output = "stdout")) }, #' - `stderr`: uses [otelsdk::tracer_provider_stdstream], to write traces #' to the standard error. "stderr" = { otelsdk::tracer_provider_stdstream$new(list(output = "stderr")) }, #' - `http` or `otlp`: uses [otelsdk::tracer_provider_http], to send #' traces through HTTP, using the OpenTelemetry Protocol (OTLP). "otlp" = , "http" = { otelsdk::tracer_provider_http$new() }, #' - `otlp/file` uses [otelsdk::tracer_provider_file] to write traces #' to a JSONL file. "otlp/file" = { otelsdk::tracer_provider_file$new() }, "jaeger" = { warning("OpenTelemetry: Jaeger trace exporter is not supported yet") tracer_provider_noop$new() }, "zipkin" = { warning("OpenTelemetry: Zipkin trace exporter is not supported yet") tracer_provider_noop$new() }, stop( "Unknown OpenTelemetry exporter from ", evar, " environment variable: ", ev ) ) } else { #' - `::`: will select the `` object from #' the `` package to use as a tracer provider. It calls #' `::$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. evx <- strsplit(ev, "::", fixed = TRUE)[[1]] pkg <- evx[1] prv <- evx[2] if (!requireNamespace(pkg, quietly = TRUE)) { stop( "Cannot set trace exporter ", ev, " from ", evar, " environment variable, cannot load package ", pkg, "." ) } if (!prv %in% names(asNamespace(pkg))) { stop( "Cannot set trace exporter ", ev, " from ", evar, " environment variable, cannot find provider ", prv, " in package ", pkg, "." ) } tp <- asNamespace(pkg)[[prv]] if ((!is.list(tp) && !is.environment(tp)) || !"new" %in% names(tp)) { stop( "Cannot set trace exporter ", ev, " from ", evar, " environment variable, it is not a list or environment with ", "a 'new' member." ) } set_default_service_name() tp$new() } the$tracer_provider <- tp invisible(tp) } #' Get the default logger provider #' #' 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. #' #' If there is no default set currently, then it creates and sets a #' default. #' #' The default logger provider is created based on the #' `r default_logs_exporter_envvar_r` environment variable. This #' environment variable is specifically for R applications with #' OpenTelemetry support. #' #' If this is not set, then the generic `r default_logs_exporter_envvar` #' environment variable is used. This applies to all applications that #' support OpenTelemetry and use the OpenTelemetry SDK. #' #' @return The default logger provider, an [otel_logger_provider] #' object. #' @family low level logs API #' @examples #' get_default_logger_provider() #' @export # safe start get_default_logger_provider <- function() { tryCatch({ # safe if (is.null(the$logger_provider)) { setup_default_logger_provider() } the$logger_provider }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe logger_provider_noop$new() # safe }) # safe } # safe end get_default_logger_provider_safe <- get_default_logger_provider #' @rdname get_default_logger_provider #' @usage NULL #' @details #' The following values are allowed: setup_default_logger_provider <- function() { evar <- default_logs_exporter_envvar_r ev <- Sys.getenv(evar, NA_character_) if (is.na(ev)) { evar <- default_logs_exporter_envvar ev <- Sys.getenv(evar, NA_character_) } tp <- if (is.na(ev)) { logger_provider_noop$new() } else if (!grepl("::", ev)) { set_default_service_name() switch( ev, #' - `none`: no traces are exported. "none" = { logger_provider_noop$new() }, #' - `stdout` or `console`: uses [otelsdk::logger_provider_stdstream], #' to write traces to the standard output. "console" = , "stdout" = { otelsdk::logger_provider_stdstream$new(list(output = "stdout")) }, #' - `stderr`: uses [otelsdk::logger_provider_stdstream], to write traces #' to the standard error. "stderr" = { otelsdk::logger_provider_stdstream$new(list(output = "stderr")) }, #' - `http` or `otlp`: uses [otelsdk::logger_provider_http], to send #' traces through HTTP, using the OpenTelemetry Protocol (OTLP). "otlp" = , "http" = { otelsdk::logger_provider_http$new() }, #' - `otlp/file` uses [otelsdk::logger_provider_file] to write logs #' to a JSONL file. "otlp/file" = { otelsdk::logger_provider_file$new() }, stop( "Unknown OpenTelemetry exporter from ", evar, " environment variable: ", ev ) ) } else { #' - `::`: will select the `` object from #' the `` package to use as a logger provider. It calls #' `::$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. evx <- strsplit(ev, "::", fixed = TRUE)[[1]] pkg <- evx[1] prv <- evx[2] if (!requireNamespace(pkg, quietly = TRUE)) { stop( "Cannot set logs exporter ", ev, " from ", evar, " environment variable, cannot load package ", pkg, "." ) } if (!prv %in% names(asNamespace(pkg))) { stop( "Cannot set logs exporter ", ev, " from ", evar, " environment variable, cannot find provider ", prv, " in package ", pkg, "." ) } tp <- asNamespace(pkg)[[prv]] if ((!is.list(tp) && !is.environment(tp)) || !"new" %in% names(tp)) { stop( "Cannot set logs exporter ", ev, " from ", evar, " environment variable, it is not a list or environment with ", "a 'new' member." ) } set_default_service_name() tp$new() } the$logger_provider <- tp invisible(tp) } #' Get the default meter 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. #' #' If there is no default set currently, then it creates and sets a #' default. #' #' The default meter provider is created based on the #' `r default_metrics_exporter_envvar_r` environment variable. This #' environment variable is specifically for R applications with #' OpenTelemetry support. #' #' If this is not set, then the generic `r default_metrics_exporter_envvar` #' environment variable is used. This applies to all applications that #' support OpenTelemetry and use the OpenTelemetry SDK. #' #' @return The default meter provider, an [otel_meter_provider] #' object. #' @family low level metrics API #' @export #' @examples #' get_default_meter_provider() # safe start get_default_meter_provider <- function() { tryCatch({ # safe if (is.null(the$meter_provider)) { setup_default_meter_provider() } the$meter_provider }, error = function(err) { # safe errmsg("OpenTelemetry error: ", conditionMessage(err)) # safe meter_provider_noop$new() # safe }) # safe } # safe end get_default_meter_provider_safe <- get_default_meter_provider #' @rdname get_default_meter_provider #' @usage NULL #' @details #' The following values are allowed: setup_default_meter_provider <- function() { evar <- default_metrics_exporter_envvar_r ev <- Sys.getenv(evar, NA_character_) if (is.na(ev)) { evar <- default_metrics_exporter_envvar ev <- Sys.getenv(evar, NA_character_) } tp <- if (is.na(ev)) { meter_provider_noop$new() } else if (!grepl("::", ev)) { set_default_service_name() switch( ev, #' - `none`: no metrics are exported. "none" = { meter_provider_noop$new() }, #' - `stdout` or `console`: uses [otelsdk::meter_provider_stdstream], #' to write metrics to the standard output. "console" = , "stdout" = { otelsdk::meter_provider_stdstream$new(list(output = "stdout")) }, #' - `stderr`: uses [otelsdk::meter_provider_stdstream], to write #' metrics to the standard error. "stderr" = { otelsdk::meter_provider_stdstream$new(list(output = "stderr")) }, #' - `http` or `otlp`: uses [otelsdk::meter_provider_http], to send #' metrics through HTTP, using the OpenTelemetry Protocol (OTLP). "otlp" = , "http" = { otelsdk::meter_provider_http$new() }, #' - `otlp/file` uses [otelsdk::meter_provider_file] to write metrics #' to a JSONL file. "otlp/file" = { otelsdk::meter_provider_file$new() }, "prometheus" = { warning("OpenTelemetry: Prometheus trace exporter is not supported yet") meter_provider_noop$new() }, stop( "Unknown OpenTelemetry exporter from ", evar, " environment variable: ", ev ) ) } else { #' - `::`: will select the `` object from #' the `` package to use as a meter provider. It calls #' `::$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. evx <- strsplit(ev, "::", fixed = TRUE)[[1]] pkg <- evx[1] prv <- evx[2] if (!requireNamespace(pkg, quietly = TRUE)) { stop( "Cannot set metrics exporter ", ev, " from ", evar, " environment variable, cannot load package ", pkg, "." ) } if (!prv %in% names(asNamespace(pkg))) { stop( "Cannot set metrics exporter ", ev, " from ", evar, " environment variable, cannot find provider ", prv, " in package ", pkg, "." ) } tp <- asNamespace(pkg)[[prv]] if ((!is.list(tp) && !is.environment(tp)) || !"new" %in% names(tp)) { stop( "Cannot set metrics exporter ", ev, " from ", evar, " environment variable, it is not a list or environment with ", "a 'new' member." ) } set_default_service_name() tp$new() } the$meter_provider <- tp invisible(tp) } otel/R/checks.R0000644000176200001440000000056715033146437013017 0ustar liggesusersis_string <- function(x) { is.character(x) && length(x) == 1 && !is.na(x) } as_string <- function(x, null = TRUE, call = NULL) { if (null & is.null(x)) { return(x) } if (is_string(x)) { return(x) } call <- call %||% match.call() stop( "Invalid argument: ", call[[2]], " must be a string scalar, but it is ", typename(x), "." ) } otel/R/friendly-type.R0000644000176200001440000001027315012446167014345 0ustar liggesusers# This is based on rlang:::obj_type_friendly, but adapted to base R friendly_type <- local({ friendly_type <- function(x, value = TRUE, length = FALSE) { if (is_missing(x)) { return("absent") } if (is.object(x)) { if (inherits(x, "quosure")) { return("a object") } else if (identical(class(x), "data.frame")) { return("a data frame") } else if (identical(class(x), c("tbl_df", "tbl", "data.frame"))) { return("a tibble") } else { # this is sometimes wrong for 'h', but ce la vie fst <- tolower(substr(class(x)[1], 1, 1)) prop <- if (fst %in% c("a", "e", "i", "o", "u")) { "an" } else { "a" } return(paste0(prop, " <", class(x)[1], "> object")) } } if (!is_vector(x)) { return(as_friendly_type(typeof(x))) } n_dim <- length(dim(x)) if (value && !n_dim) { if (is_na(x)) { return(switch( typeof(x), logical = "`NA`", integer = "an integer `NA`", double = "a numeric `NA`", complex = "a complex `NA`", character = "a character `NA`", typeof(x) )) } if (length(x) == 1 && !is_list(x)) { return(switch( typeof(x), logical = if (x) "`TRUE`" else "`FALSE`", integer = "an integer", double = "a number", complex = "a complex number", character = if (nzchar(x)) "a string" else "`\"\"`", raw = "a raw value", sprintf("a %s value", typeof(x)) )) } if (length(x) == 0) { return(switch( typeof(x), logical = "an empty logical vector", integer = "an empty integer vector", double = "an empty numeric vector", complex = "an empty complex vector", character = "an empty character vector", raw = "an empty raw vector", list = "an empty list", sprintf("a %s of length one", typeof(x)) )) } } type <- friendly_vector_type(typeof(x), n_dim) if (length && !n_dim) { type <- paste0(type, sprintf(" of length %s", length(x))) } type } friendly_vector_type <- function(type, n_dim) { if (type == "list") { if (n_dim < 2) { return("a list") } else if (n_dim == 2) { return("a list matrix") } else { return("a list array") } } type <- switch( type, logical = "a logical %s", integer = "an integer %s", numeric = , double = "a double %s", complex = "a complex %s", character = "a character %s", raw = "a raw %s", type = paste0("a ", type, " %s") ) if (n_dim < 2) { kind <- "vector" } else if (n_dim == 2) { kind <- "matrix" } else { kind <- "array" } sprintf(type, kind) } as_friendly_type <- function(type) { switch( type, list = "a list", NULL = "NULL", environment = "an environment", externalptr = "a pointer", weakref = "a weak reference", S4 = "an S4 object", name = , symbol = "a symbol", language = "a call", pairlist = "a pairlist node", expression = "an expression vector", char = "an internal string", promise = "an internal promise", ... = "an internal dots object", any = "an internal `any` object", bytecode = "an internal bytecode object", primitive = , builtin = , special = "a primitive function", closure = "a function", type ) } is_missing <- function(x) { missing(x) || identical(x, quote(expr = )) } is_vector <- function(x) { t <- typeof(x) t %in% c( "logical", "integer", "double", "complex", "character", "raw", "list" ) } is_scalar_vector <- function(x) { is_vector(x) && length(x) == 1L } is_na <- function(x) { is_scalar_vector(x) && is.na(x) } is_list <- function(x) { typeof(x) == "list" } list( .internal = environment(), friendly_type = friendly_type ) }) typename <- friendly_type$friendly_type otel/R/api-dev.R0000644000176200001440000001402515053315013013064 0ustar liggesusers get_tracer_dev <- function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { # does setup if necessary provider <- provider %||% get_default_tracer_provider() trc <- provider$get_tracer(name, version, schema_url, attributes, ...) invisible(trc) } get_logger_dev <- function( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { # does setup if necessary provider <- provider %||% get_default_logger_provider() lgr <- provider$get_logger( name, minimum_severity, version, schema_url, attributes, ... ) invisible(lgr) } get_meter_dev <- function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) { # does setup if necessary provider <- provider %||% get_default_meter_provider() mtr <- provider$get_meter(name, version, schema_url, attributes, ...) invisible(mtr) } local_active_span_dev <- function( span, end_on_exit = FALSE, activation_scope = parent.frame() ) { invisible(span$activate(activation_scope, end_on_exit = end_on_exit)) } with_active_span_dev <- function(span, expr, end_on_exit = FALSE) { local({ invisible(span$activate(end_on_exit = end_on_exit)) expr }) } get_active_span_dev <- function() { trc <- get_tracer() trc$get_active_span() } get_active_span_context_dev <- function() { trc <- get_tracer() trc$get_active_span_context() } pack_http_context_dev <- function() { trc <- get_tracer() trc$get_active_span_context()$to_http_headers() } extract_http_context_dev <- function(headers) { trc <- get_tracer() trc$extract_http_context(headers) } start_span_dev <- function( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL ) { if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } invisible(tracer$start_span(name, attributes, links, options, ...)) } end_span_dev <- function(span) { identity(NULL) span$end() } start_local_active_span_dev <- function( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL, activation_scope = parent.frame(), end_on_exit = TRUE ) { if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } span <- tracer$start_span(name, attributes, links, options, ...) span$activate( activation_scope = activation_scope, end_on_exit = end_on_exit) invisible(span) } is_tracing_enabled_dev <- function(tracer = NULL) { if (!inherits(tracer, "otel_tracer")) { tracer <- get_tracer(tracer) } tracer$is_enabled() } is_logging_enabled_dev <- function(severity = "info", logger = NULL) { if (!inherits(logger, "otel_tracer")) { logger <- get_logger(logger) } logger$is_enabled(severity) } is_measuring_enabled_dev <- function(meter = NULL) { if (!inherits(meter, "otel_meter")) { meter <- get_meter(meter) } meter$is_enabled() } log_dev <- function( msg, ..., severity = "info", logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, severity, ...) invisible(logger) } log_trace_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "trace", ...) invisible(logger) } log_debug_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "debug", ...) invisible(logger) } log_info_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "info", ...) invisible(logger) } log_warn_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "warn", ...) invisible(logger) } log_error_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "error", ...) invisible(logger) } log_fatal_dev <- function( msg, ..., logger = NULL ) { if (!inherits(logger, "otel_logger")) { logger <- get_logger() } logger$log(msg, "fatal", ...) invisible(logger) } counter_add_dev <- function( name, value = 1L, attributes = NULL, context = NULL, meter = NULL ) { if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_counter(name) ctr$add(value, attributes, context) invisible(ctr) } up_down_counter_add_dev <- function( name, value = 1L, attributes = NULL, context = NULL, meter = NULL ) { if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_up_down_counter(name) ctr$add(value, attributes, context) invisible(ctr) } histogram_record_dev <- function( name, value, attributes = NULL, context = NULL, meter = NULL ) { if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_histogram(name) ctr$record(value, attributes, context) invisible(ctr) } gauge_record_dev <- function( name, value, attributes = NULL, context = NULL, meter = NULL ) { if (!inherits(meter, "otel_meter")) { meter <- get_meter() } ctr <- meter$create_gauge(name) ctr$record(value, attributes, context) invisible(ctr) } get_default_tracer_provider_dev <- function() { if (is.null(the$tracer_provider)) { setup_default_tracer_provider() } the$tracer_provider } get_default_logger_provider_dev <- function() { if (is.null(the$logger_provider)) { setup_default_logger_provider() } the$logger_provider } get_default_meter_provider_dev <- function() { if (is.null(the$meter_provider)) { setup_default_meter_provider() } the$meter_provider } otel/R/docs.R0000644000176200001440000001323015042430744012473 0ustar liggesusers#' @name Getting Started #' @title Getting Started #' @rdname gettingstarted #' @aliases gettingstarted #' @description #' This page is about instrumenting you R package or project for #' OpenTelemetry. If you want to start collecting OpenTelemetry data #' for instrumented packages, see \link[otelsdk:Collecting Telemetry Data]{ #' Collecting Telemetry Data} in the otelsdk package. #' #' @details #' ```{r child = "tools/dox/gettingstarted.Rmd"} #' ``` #' #' @examples #' # See above NULL doc_evs_exporter <- function() { c( default_traces_exporter_envvar, default_traces_exporter_envvar_r, default_logs_exporter_envvar, default_logs_exporter_envvar_r, default_metrics_exporter_envvar, default_metrics_exporter_envvar_r ) } doc_evs_suppress <- function() { c( otel_emit_scopes_envvar, otel_suppress_scopes_envvar ) } doc_evs <- function() { paste( collapse = " ", c( doc_evs_exporter(), doc_evs_suppress() ) ) } #' Environment variables to configure otel #' @name Environment Variables #' @rdname environmentvariables #' @eval paste("@aliases", "OTEL_ENV", doc_evs()) #' #' @description #' This manual page contains the environment variables you can use to #' configure the otel package. #' #' See also the \link[otelsdk:Environment Variables]{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. #' #' # Production or Development Environment #' #' * `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. #' #' ```{r child = system.file(package = "otel", "dox/ev-exporters.Rmd")} #' ``` #' #' ```{r child = system.file(package = "otel", "dox/ev-suppress.Rmd")} #' ``` #' #' ```{r child = system.file(package = "otel", "dox/ev-zci.Rmd")} #' ``` #' #' ```{r child = system.file(package = "otel", "dox/ev-others.Rmd")} #' ``` #' #' @return Not applicable. #' @seealso \link[otelsdk:Environment Variables]{Environment Variables} in #' otelsdk #' @examples #' # To start an R session using the OTLP exporter: #' # OTEL_TRACES_EXPORTER=http R -q -f script.R NULL #' Zero Code Instrumentation #' #' 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__INCLUDE` environment variable to a list of #' glob expressions. `` 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__EXCLUDE` environment variable to a list of #' glob expressions. `` 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. #' #' ## Caveats #' #' If the user calls [base::trace()] on an instrumented function, that #' deletes the instrumentation, since the second [base::trace()] call #' overwrites the first. #' #' @name Zero Code Instrumentation #' @rdname zci #' @family OpenTelemetry trace API #' @seealso [Environment Variables] #' @return Not applicable. #' @aliases OTEL_R_INSTRUMENT_PKGS #' @examples #' # To run an R script with ZCI: #' # OTEL_TRACES_EXPORTER=http OTEL_INSTRUMENT_R_PKGS=dplyr,tidyr R -q -f script.R NULL doc_arg <- function() { list( "span-name" = "Name of the span. If not specified it will be `\"\"`.", 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.", attributes = glue::glue( trim = FALSE, "Span attributes. OpenTelemetry supports the following R types as attributes: `{paste0(otel_attr_types, collapse = \", \")}. You may use [as_attributes()] to convert other R types to OpenTelemetry attributes." ), # need to use \itemize, markdown does not put this list under the other # one for otel_tracer method arguments "span-options" = glue::glue( trim = FALSE, "A named list of span options. May include: \\itemize{{ \\item `start_system_time`: Start time in system time. \\item `start_steady_time`: Start time using a steady clock. \\item `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. \\item `kind`: Span kind, one of [span_kinds]: {paste(dQuote(span_kinds, q = FALSE), collapse = ', ')}.}}" ), "unit" = "Optional measurement unit. If specified, it should use units from [Unified Code for Units of Measure](https://ucum.org/), according to the [OpenTelemetry semantic conventions]( https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units)." ) } otel/R/meter-provider-noop.R0000644000176200001440000003550315046452776015504 0ustar liggesusers#' OpenTelemetry meter provider objects #' #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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]. #' #' # Implementations #' #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `meter_provider$get_meter()` #' #' Get or create a new meter object. #' #' ### Usage #' #' ```r #' meter_provider$get_meter( #' name = NULL, #' version = NULL, #' schema_url = NULL, #' attributes = NULL #' ) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' Returns an OpenTelemetry meter ([otel_meter]) object. #' #' ### See also #' #' [get_default_meter_provider()], [get_meter()]. #' # ------------------------------------------------------------------------- #' ## `meter_provider$flush()` #' #' Force any buffered metrics to flush. Meter providers might not implement #' this method. #' #' ### Usage #' #' ``` #' meter_provider$flush() #' ``` #' #' ### Value #' #' Nothing. #' # ------------------------------------------------------------------------- #' ## `meter_provider$shutdown()` #' #' Stop the meter provider. Stops collecting and emitting measurements. #' #' ### Usage #' #' ```r #' meter_provider$shurdown() #' ``` #' #' ### Value #' #' Nothing #' #' @name otel_meter_provider #' @family low level metrics API #' @return Not applicable. #' @examples #' mp <- otel::get_default_meter_provider() #' mtr <- mp$get_meter() #' mtr$is_enabled() NULL #' No-op Meter Provider #' #' 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. #' #' @family low level metrics API #' @usage NULL #' @format NULL #' @export #' @return Not applicable. #' @examples #' meter_provider_noop$new() meter_provider_noop <- list( new = function() { self <- structure( list( get_meter = function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) { meter_noop$new( name = name, version = version, schema_url = schema_url, attributes = attributes ) }, flush = function(timeout = NULL, ...) { # noop invisible(self) }, shutdown = function(timeout = NULL, ...) { # noop invisible(self) }, get_metrics = function() { list() } ), class = c( "otel_meter_provider_noop", "otel_meter_provider" ) ) self } ) #' OpenTelemetry Meter Object #' @name otel_meter #' @family low level metrics API #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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. #' #' # Methods #' # ------------------------------------------------------------------------- #' ## `meter$is_enabled()` #' #' Whether the meter is active and emitting measurements. #' #' This is equivalent to the [is_measuring_enabled()] function. #' #' ### Usage #' #' ```r #' meter$is_enabled() #' ``` #' #' ### Value #' #' Logical scalar. #' # ------------------------------------------------------------------------- #' ## `meter$create_counter()` #' #' Create a new [counter instrument]( #' https://opentelemetry.io/docs/specs/otel/metrics/api/#counter). #' #' ### Usage #' #' ```r #' create_counter(name, description = NULL, unit = NULL) #' ``` #' #' ### Arguments #' #' - `name`: Name of the instrument. #' - `description`: Optional description. #' - `unit`: `r doc_arg()[["unit"]]` #' #' ### Value #' #' An OpenTelemetry counter ([otel_counter]) object. #' # ------------------------------------------------------------------------- #' ## `meter$create_up_down_counter()` #' #' Create a new [up-down counter instrument]( #' https://opentelemetry.io/docs/specs/otel/metrics/api/#updowncounter). #' #' ### Usage #' #' ```r #' create_up_down_counter(name, description = NULL, unit = NULL) #' ``` #' #' ### Arguments #' #' - `name`: Name of the instrument. #' - `description`: Optional description. #' - `unit`: `r doc_arg()[["unit"]]` #' #' ### Value #' #' An OpenTelemetry counter ([otel_up_down_counter]) object. #' # ------------------------------------------------------------------------- #' ## `meter$create_histogram()` #' #' Create a new [histogram]( #' https://opentelemetry.io/docs/specs/otel/metrics/api/#histogram). #' #' ### Usage #' #' ```r #' create_histogram(name, description = NULL, unit = NULL) #' ``` #' #' ### Arguments #' #' - `name`: Name of the instrument. #' - `description`: Optional description. #' - `unit`: `r doc_arg()[["unit"]]` #' #' ### Value #' #' An OpenTelemetry histogram ([otel_histogram]) object. #' # ------------------------------------------------------------------------- #' ## `meter$create_gauge()` #' #' Create a new [gauge]( #' https://opentelemetry.io/docs/specs/otel/metrics/api/#gauge). #' #' ### Usage #' #' ```r #' create_gauge(name, description = NULL, unit = NULL) #' ``` #' #' ### Arguments #' #' - `name`: Name of the instrument. #' - `description`: Optional description. #' - `unit`: `r doc_arg()[["unit"]]` #' #' ### Value #' #' An OpenTelemetry gauge ([otel_gauge]) object. #' #' @return Not applicable. #' @examples #' mp <- get_default_meter_provider() #' mtr <- mp$get_meter() #' ctr <- mtr$create_counter("session") #' ctr$add(1) NULL meter_noop <- list( new = function( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) { self <- structure( list( create_counter = function( name, description = NULL, unit = NULL ) { counter_noop$new(name, description, unit) }, create_up_down_counter = function( name, description = NULL, unit = NULL ) { up_down_counter_noop$new(name, description, unit) }, create_histogram = function( name, description = NULL, unit = NULL ) { histogram_noop$new(name, description, unit) }, create_gauge = function( name, description = NULL, unit = NULL ) { gauge_noop$new(name, description, unit) }, is_enabled = function() FALSE ), class = c("otel_meter_noop", "otel_meter") ) self } ) #' OpenTelemetry Counter Object #' #' @name otel_counter #' @family low level metrics API #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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. #' #' # Methods #' #' ## `counter$add()` #' #' Increment the counter by a fixed amount. #' #' ### Usage #' #' ```r #' counter$add(value, attributes = NULL, span_context = NULL, ...) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' The counter object itself, invisibly. #' #' @return Not applicable. #' @examples #' mp <- get_default_meter_provider() #' mtr <- mp$get_meter() #' ctr <- mtr$create_counter("session") #' ctr$add(1) NULL counter_noop <- list( new = function(name = NULL, ...) { self <- structure( list( add = function(value, attributes = NULL, span_context = NULL, ...) { invisible(self) } ), class = c("otel_counter_noop", "otel_counter") ) self } ) #' OpenTelemetry Up-Down Counter Object #' #' @name otel_up_down_counter #' @family low level metrics API #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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. #' #' # Methods #' #' ## `up_down_counter$add()` #' #' Increment or decrement the up-down counter by a fixed amount. #' #' ### Usage #' #' ```r #' up_down_counter$add(value, attributes = NULL, span_context = NULL, ...) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' The up-down counter object itself, invisibly. #' #' @return Not applicable. #' @examples #' mp <- get_default_meter_provider() #' mtr <- mp$get_meter() #' ctr <- mtr$create_up_down_counter("session") #' ctr$add(1) NULL up_down_counter_noop <- list( new = function(name = NULL, ...) { self <- structure( list( add = function(value, attributes = NULL, span_context = NULL, ...) { invisible(self) } ), class = c("otel_up_down_counter_noop", "otel_up_down_counter") ) self } ) #' OpenTelemetry Histogram Object #' #' @name otel_histogram #' @family low level metrics API #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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. #' #' # Methods #' #' ## `histogram$record()` #' #' Update the statistics with the specified amount. #' #' ### Usage #' #' ```r #' histogram$record(value, attributes = NULL, span_context = NULL, ...) #' ``` #' #' ### Arguments #' #' - `value`: A numeric value to record. #' - `attributes`: Additional attributes to add. #' - `span_context`: Span context. If missing, the active context is used, #' if any. #' #' ### Value #' #' The histogram object itself, invisibly. #' #' @return Not applicable. #' @examples #' mp <- get_default_meter_provider() #' mtr <- mp$get_meter() #' hst <- mtr$create_histogram("response-time") #' hst$record(1.123) NULL histogram_noop <- list( new = function(name = NULL, ...) { self <- structure( list( record = function(value, attributes = NULL, span_context = NULL, ...) { invisible(self) } ), class = c("otel_histogram_noop", "otel_histogram") ) self } ) #' OpenTelemetry Gauge Object #' #' @name otel_gauge #' @family low level metrics API #' @description #' [otel_meter_provider] -> [otel_meter] -> [otel_counter], #' [otel_up_down_counter], [otel_histogram], [otel_gauge] #' #' @details #' 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. #' #' # Methods #' #' ## `gauge$record()` #' #' Update the statistics with the specified amount. #' #' ### Usage #' #' ```r #' gauge$record(value, attributes = NULL, span_context = NULL, ...) #' ``` #' #' ### Arguments #' #' - `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. #' #' ### Value #' #' The gauge object itself, invisibly. #' #' @return Not applicable. #' @examples #' mp <- get_default_meter_provider() #' mtr <- mp$get_meter() #' gge <- mtr$create_gauge("response-time") #' gge$record(1.123) NULL gauge_noop <- list( new = function(name = NULL, ...) { self <- structure( list( record = function(value, attributes = NULL, span_context = NULL, ...) { invisible(self) } ), class = c("otel_gauge_noop", "otel_gauge") ) } ) otel/NAMESPACE0000644000176200001440000000333615051664453012452 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(format,otel_counter) S3method(format,otel_gauge) S3method(format,otel_histogram) S3method(format,otel_logger) S3method(format,otel_logger_provider) S3method(format,otel_meter) S3method(format,otel_meter_provider) S3method(format,otel_span) S3method(format,otel_span_context) S3method(format,otel_tracer) S3method(format,otel_tracer_provider) S3method(format,otel_up_down_counter) S3method(print,otel_counter) S3method(print,otel_gauge) S3method(print,otel_histogram) S3method(print,otel_logger) S3method(print,otel_logger_provider) S3method(print,otel_meter) S3method(print,otel_meter_provider) S3method(print,otel_span) S3method(print,otel_span_context) S3method(print,otel_tracer) S3method(print,otel_tracer_provider) S3method(print,otel_up_down_counter) export(as_attributes) export(counter_add) export(default_tracer_name) export(end_span) export(extract_http_context) export(gauge_record) export(get_active_span) export(get_active_span_context) export(get_default_logger_provider) export(get_default_meter_provider) export(get_default_tracer_provider) export(get_logger) export(get_meter) export(get_tracer) export(histogram_record) export(invalid_span_id) export(invalid_trace_id) export(is_logging_enabled) export(is_measuring_enabled) export(is_tracing_enabled) export(local_active_span) export(log) export(log_debug) export(log_error) export(log_fatal) export(log_info) export(log_severity_levels) export(log_trace) export(log_warn) export(logger_provider_noop) export(meter_provider_noop) export(pack_http_context) export(span_kinds) export(span_status_codes) export(start_local_active_span) export(start_span) export(tracer_provider_noop) export(up_down_counter_add) export(with_active_span) otel/LICENSE0000644000176200001440000000005214766244316012234 0ustar liggesusersYEAR: 2025 COPYRIGHT HOLDER: otel authors otel/NEWS.md0000644000176200001440000000030215054320403012302 0ustar liggesusers# otel 0.2.0 * Zero Code Instrumentation (ZCI) works again (#20). * The interpolation of R expressions in log messages is not supported any more (#21). # otel 0.1.0 First release on CRAN. otel/inst/0000755000176200001440000000000015046400571012174 5ustar liggesusersotel/inst/dox/0000755000176200001440000000000015042355474012775 5ustar liggesusersotel/inst/dox/gs.Rmd0000644000176200001440000000102715041005443014035 0ustar liggesusers## Getting started ```{r} #| include: FALSE gslink <- if (Sys.getenv("IN_PKGDOWN") == "true") { "reference/gettingstarted.html" } else { "https://otel.r-lib.org/reference/gettingstarted.html" } ``` Set `otel_tracer_name` to the desired tracer name. (See `?otel_tracer_name`.) Then add `otel::start_local_active_span()` calls to the functions you want to trace: ```r otel_tracer_name <- "" fn <- function(...) { spn <- otel::start_local_active_span("fn") ... } ``` See [Getting Started](`r gslink`) for details. otel/inst/dox/packages.Rmd0000644000176200001440000000053015040120544015177 0ustar liggesusers## The otel and otelsdk R packages Use the [otel](https://github.com/r-lib/otel) package as a dependency if you want to instrument your R package or project for OpenTelemetry. Use the [otelsdk](https://github.com/r-lib/otelsdk) package to produce OpenTelemetry output from an R package or project that was instrumented with the otel package. otel/inst/dox/ev-suppress.Rmd0000644000176200001440000000277115042430616015734 0ustar liggesusers# Suppressing Instrumentation Scopes (R Packages) 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. * ``r otel:::otel_emit_scopes_envvar`` 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 [otel::default_tracer_name()]. You can mix package names and instrumentation scope names and you can also use wildcards (globbing). For example the value `r paste0(otel:::otel_emit_scopes_envvar, '="org.r-lib.*,dplyr"')` selects all packages with an instrumentation scope that starts with `org.r-lib.` and also dplyr. * ``r otel:::otel_suppress_scopes_envvar`` 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 [otel::default_tracer_name()]. You can mix package names and instrumentation scope names and you can also use wildcards (globbing). For example the value `r paste0(otel:::otel_suppress_scopes_envvar, '="org.r-lib.*,dplyr"')` excludes packages with an instrumentation scope that starts with `org.r-lib.` and also dplyr. otel/inst/dox/version-support.Rmd0000644000176200001440000000036715040373141016633 0ustar liggesusers## Version support ```{r} #| include: FALSE dps <- desc::desc(package = "otel")$get_deps() rdp <- trimws(sub(">=", "", dps$version[dps$package == "R"])) ``` otel and otelsdk support R `r rdp` and higher on Unix and R 4.3.0 or higher on Windows. otel/inst/dox/ev-exporters.Rmd0000644000176200001440000000215615042430473016101 0ustar liggesusers# Selecting Exporters 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. * ``r otel:::default_traces_exporter_envvar`` The name of the selected tracer provider. See [otel::get_default_tracer_provider()] for the possible values. * ``r otel:::default_traces_exporter_envvar_r`` R specific version of ``r otel:::default_traces_exporter_envvar``. * ``r otel:::default_logs_exporter_envvar`` The name of the selected logger provider. See [otel::get_default_logger_provider()] for the possible values. * ``r otel:::default_logs_exporter_envvar_r`` R specific version of ``r otel:::default_logs_exporter_envvar``. * ``r otel:::default_metrics_exporter_envvar`` The name of the selected meter provider. See [otel::get_default_meter_provider()] for the possible values. * ``r otel:::default_metrics_exporter_envvar_r`` R specific version of ``r otel:::default_metrics_exporter_envvar``. otel/inst/dox/status.Rmd0000644000176200001440000000072215040120571014747 0ustar liggesusers## Status The current status of the major functional components for OpenTelemetry R is as follows: ```{R} #| include: FALSE link_base <- "https://opentelemetry.io/docs/specs/otel" link <- paste0(link_base, "/versioning-and-stability/#development") ``` *Traces* | *Metrics* | *Logs* ------------------------+-------------------------|------------------------ [Development](`r link`) | [Development](`r link`) | [Development](`r link`) otel/inst/dox/features.Rmd0000644000176200001440000000122015040120520015226 0ustar liggesusers## Features * Lightweight packages. otel is a small R package without dependencies and compiled code. otelsdk needs a C++11 compiler and otel. * Minimal performance impact when tracing is disabled. otel functions do not evaluate their arguments in this case. * Zero-code instrumentation support. Add tracing to (some) functions of selected packages automatically. * Configuration via environment variables. * Minimal extra code. Add tracing to a function with a single extra function call. * Production mode: otel functions do not crash your production app in production mode. * Development mode: otel functions error early in development mode. otel/inst/dox/ev-zci.Rmd0000644000176200001440000000215615042430664014635 0ustar liggesusers# [Zero Code Instrumentation][otel::Zero Code Instrumentation] 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__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__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/inst/dox/ev-others.Rmd0000644000176200001440000000134215042430567015352 0ustar liggesusers# Attribute Limits * ``r otel:::otel_attr_cnt_limit_var`` 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 `r otel:::otel_attr_cnt_limit_dflt` attributes. Note that only attributes specified with [otel::as_attributes()] are subject to this environment variable. * ``r otel:::otel_attr_val_lth_limit_var`` 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 [otel::as_attributes()] are subject to this environment variable. otel/inst/dox/reference-docs.Rmd0000644000176200001440000000016615040761302016315 0ustar liggesusers## Reference Documentation * otel: https://otel.r-lib.org/reference/ * otelsdk: https://otelsdk.r-lib.org/reference/ otel/inst/dox/intro.Rmd0000644000176200001440000000113415041620432014557 0ustar liggesusers```{r} #| include: FALSE gslink <- if (Sys.getenv("IN_PKGDOWN") == "true") { "reference/gettingstarted.html" } else { "https://otel.r-lib.org/reference/gettingstarted.html" } ``` OpenTelemetry is an observability framework. [OpenTelemetry]( https://opentelemetry.io/) 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](https://opentelemetry.io/docs/). otel/inst/dox/Architecture.Rmd0000644000176200001440000001221215041006440016042 0ustar liggesusers# Architecture ## Instrumented R package with tracing disabled All `otel::` calls are no-operations. ``` ┌─────────────────┐ │ R package │ ├─⇩───────────────┤ │ otel package │ └─────────────────┘ ``` ## Instrumented R package with tracing enabled Use environment variables to select the OpenTelemetry exporter to switch on. Exporters are in the otelsdk package. Use environment variables to configure the selected exporter(s). E.g. the URL to send the data to. ``` ┌─────────────────┐ │ R package │ ╭────────╮ ├─⇩───────────────┤ │env vars│───→│ otel package │ ╰────────╯ ├─⇩───────────────┤ └──────→│ otelsdk package │ ├─⇩───────────────┤ │opentelemetry-cpp│ └─────────────────┘ ``` #### Exporting OpenTelemetry data via OTLP/HTTP: The `http` exporter sends OpenTelemetry data using OTLP/HTTP to a collector. ``` ┌─────────────────┐ │ R package │ ┊ ╭────────╮ ├─⇩───────────────┤ ┊ │env vars│───→│ otel package │ ┊ ╰────────╯ ├─⇩───────────────┤ ┊ └──────→│ otelsdk package │ ┊ ╔═══════════════╗ ├─⇩───────────────┤ ┊ ║ opentelemetry ║ │opentelemetry-cpp├──────── OTLP ─────────────→║ collector ║ └─────────────────┘ ┊ ╚═══════════════╝ ``` #### Context propagation to subprocess callr sets the `TRACEPARENT` environment variable, that contains the OpenTelemetry (span) context, in the main process. The subprocess creates a child span of this: ``` ┌─────────────────┐callr┌────────────┐ │ R package │────→│ subprocess │ ┊ ╭────────╮ ├─⇩───────────────┤ └────────────┘ ┊ │env vars│───→│ otel package │ │OTLP ┊ ╰────────╯ ├─⇩───────────────┤ │ ┊ └──────→│ otelsdk package │ │ ┊ ╔═══════════════╗ ├─⇩───────────────┤ └────────────→║ opentelemetry ║ │opentelemetry-cpp├──────── OTLP ─────────────→║ collector ║ └─────────────────┘ ┊ ╚═══════════════╝ ``` #### Context propagation through HTTP httr2 sets the `TRACEPARENT` HTTP header, that contains the OpenTelemetry (span) context. The web server creates a child span of this. ``` ┌─────────────────┐callr┌────────────┐ ┊ ┌────────────┐ │ R package │────→│ subprocess │ ┌───────→│ web server │ ╭────────╮ ├─⇩───────────────┤ └────────────┘ │ ┊ └────────────┘ │env vars│───→│ otel package │──────────────┼─────┘ ┊┄┄┄┄┄┄┄┄┄┄┄┄┄│┄┄┄┄┄┄┄┄┄ ╰────────╯ ├─⇩───────────────┤httr2 │ ┊ │ └──────→│ otelsdk package │ │ ┊ ╔══════ ↓ ══════╗ ├─⇩───────────────┤ └────────────→║ opentelemetry ║ │opentelemetry-cpp├──────── OTLP ─────────────→║ collector ║ └─────────────────┘ ┊ ╚═══════════════╝ ``` otel/inst/dox/repositories.Rmd0000644000176200001440000000014315040120762016152 0ustar liggesusers## Repositories * otel: https://github.com/r-lib/otel * otelsdk: https://github.com/r-lib/otelsdk otel/inst/air.toml0000644000176200001440000000012415051544043013640 0ustar liggesusers[format] exclude = ["R/api.R", "R/shiny.R", "R/defaults.R", "R/api-dev.R", ".dev/*"]otel/inst/WORDLIST0000644000176200001440000000026615041007631013365 0ustar liggesusersCMD Codecov JSONL OTLP OpenTelemetry PBC SDK SDKs ZCI callr deserialize dplyr finalizer globbing http lifecycle natively noop observability otelsdk stdstream subprocess subprocesses otel/README.md0000644000176200001440000001026415054315405012501 0ustar liggesusers # otel > OpenTelemetry API for R packages and projects ![lifecycle](https://lifecycle.r-lib.org/articles/figures/lifecycle-experimental.svg) [![R-CMD-check](https://github.com/r-lib/otel/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/otel/actions/workflows/R-CMD-check.yaml) [![R-CMD-check](https://github.com/r-lib/otel/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/otel/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/r-lib/otel/graph/badge.svg)](https://app.codecov.io/gh/r-lib/otel) OpenTelemetry is an observability framework. [OpenTelemetry](https://opentelemetry.io/) 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](https://opentelemetry.io/docs/). To learn how to instrument your R code, see [Getting Started](https://otel.r-lib.org/reference/gettingstarted.html). For project status, installation instructions and more, read on. ## Features - Lightweight packages. otel is a small R package without dependencies and compiled code. otelsdk needs a C++11 compiler and otel. - Minimal performance impact when tracing is disabled. otel functions do not evaluate their arguments in this case. - Zero-code instrumentation support. Add tracing to (some) functions of selected packages automatically. - Configuration via environment variables. - Minimal extra code. Add tracing to a function with a single extra function call. - Production mode: otel functions do not crash your production app in production mode. - Development mode: otel functions error early in development mode. ## Getting started Set `otel_tracer_name` to the desired tracer name. (See `?otel_tracer_name`.) Then add `otel::start_local_active_span()` calls to the functions you want to trace: ``` r otel_tracer_name <- "" fn <- function(...) { spn <- otel::start_local_active_span("fn") ... } ``` See [Getting Started](https://otel.r-lib.org/reference/gettingstarted.html) for details. ## The otel and otelsdk R packages Use the [otel](https://github.com/r-lib/otel) package as a dependency if you want to instrument your R package or project for OpenTelemetry. Use the [otelsdk](https://github.com/r-lib/otelsdk) package to produce OpenTelemetry output from an R package or project that was instrumented with the otel package. ## Reference Documentation - otel: - otelsdk: ## Status The current status of the major functional components for OpenTelemetry R is as follows: | *Traces* | *Metrics* | *Logs* | |-----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| | [Development](https://opentelemetry.io/docs/specs/otel/versioning-and-stability/#development) | [Development](https://opentelemetry.io/docs/specs/otel/versioning-and-stability/#development) | [Development](https://opentelemetry.io/docs/specs/otel/versioning-and-stability/#development) | ## Version support otel and otelsdk support R 3.6.0 and higher on Unix and R 4.3.0 or higher on Windows. ## Installation Install otel from CRAN: ``` r # install.packages("pak") pak::pak("otel") ``` You can install the development version of otel from [GitHub](https://github.com/) with: ``` r # install.packages("pak") pak::pak("r-lib/otel") ``` ## Repositories - otel: - otelsdk: ## License MIT © Posit, PBC otel/man/0000755000176200001440000000000015051666774012011 5ustar liggesusersotel/man/otel_span_context.Rd0000644000176200001440000001014315046400601016002 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-provider-noop.R \name{otel_span_context} \alias{otel_span_context} \title{An OpenTelemetry Span Context object} \value{ Not applicable. } \description{ \link{otel_tracer_provider} -> \link{otel_tracer} -> \link{otel_span} -> \link{otel_span_context} } \details{ 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. } \section{Methods}{ \subsection{\code{span_context$get_span_id()}}{ Get the id of the span. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$get_span_id() }\if{html}{\out{
}} } \subsection{Value}{ String scalar, a span id. For invalid spans it is \link{invalid_span_id}. } } \subsection{\code{span_context$get_trace_flags()}}{ Get the trace flags of a span. See the \href{https://w3c.github.io/trace-context/#trace-flags}{specification} for more details on trace flags. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$get_trace_flags() }\if{html}{\out{
}} } \subsection{Value}{ A list with entries: \itemize{ \item \code{is_sampled}: logical flag, whether the trace of the span is sampled. If \code{FALSE} then the caller is not recording the trace. See details in the \href{https://w3c.github.io/trace-context/#sampled-flag}{specification}. \item \code{is_random}: logical flag, it specifies how trace ids are generated. See details in the \href{https://w3c.github.io/trace-context/#random-trace-id-flag}{specification}. } } } \subsection{\code{span_context$get_trace_id()}}{ Get the id of the trace the span belongs to. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$get_trace_id() }\if{html}{\out{
}} } \subsection{Value}{ A string scalar, a trace id. For invalid spans it is \link{invalid_trace_id}. } } \subsection{\code{span_context$is_remote()}}{ Whether the span was propagated from a remote parent. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$is_remote() }\if{html}{\out{
}} } \subsection{Value}{ A logical scalar. } } \subsection{\code{span_context$is_sampled()}}{ Whether the span is sampled. This is the same as the \code{is_sampled} trace flags, see \code{get_trace_flags()} above. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$is_sampled() }\if{html}{\out{
}} } \subsection{Value}{ Logical scalar. } } \subsection{\code{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. \code{\link[=get_active_span_context]{get_active_span_context()}} does that if there is no active span. \code{is_valid()} checks if the span is valid. An span id of an invalid span is \link{invalid_span_id}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$is_valid() }\if{html}{\out{
}} } \subsection{Value}{ A logical scalar. } } \subsection{\code{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. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span_context$to_http_headers() }\if{html}{\out{
}} } \subsection{Value}{ A named character vector, the HTTP header representation of the span context. Usually includes a \code{traceparent} header. May include other headers. } } } \examples{ 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() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{get_tracer}()}, \code{\link{otel_span}}, \code{\link{otel_tracer}}, \code{\link{otel_tracer_provider}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/start_span.Rd0000644000176200001440000000664615046400601014445 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{start_span} \alias{start_span} \title{Start an OpenTelemetry span.} \usage{ start_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL ) } \arguments{ \item{name}{Name of the span. If not specified it will be \code{""}.} \item{attributes}{Span attributes. OpenTelemetry supports the following R types as attributes: `character, logical, double, integer. You may use \code{\link[=as_attributes]{as_attributes()}} to convert other R types to OpenTelemetry attributes.} \item{links}{A named list of links to other spans. Every link must be an OpenTelemetry span (\link{otel_span}) object, or a list with a span object as the first element and named span attributes as the rest.} \item{options}{A named list of span options. May include: \itemize{ \item \code{start_system_time}: Start time in system time. \item \code{start_steady_time}: Start time using a steady clock. \item \code{parent}: A parent span or span context. If it is \code{NA}, then the span has no parent and it will be a root span. If it is \code{NULL}, then the current context is used, i.e. the active span, if any. \item \code{kind}: Span kind, one of \link{span_kinds}: "internal", "server", "client", "producer", "consumer".}} \item{...}{Additional arguments are passed to the \code{start_span()} method of the tracer.} \item{tracer}{A tracer object or the name of the tracer to use, see \code{\link[=get_tracer]{get_tracer()}}. If \code{NULL} then \code{\link[=default_tracer_name]{default_tracer_name()}} is used.} } \value{ An OpenTelemetry span (\link{otel_span}). } \description{ Creates a new OpenTelemetry span and starts it, without activating it. Usually you want \code{\link[=start_local_active_span]{start_local_active_span()}} instead of \code{start_span}. \code{\link[=start_local_active_span]{start_local_active_span()}} also activates the span for the caller frame, and ends the span when the caller frame exits. } \details{ Only use \code{start_span()} is you need to manage the span's activation manually. Otherwise use \code{\link[=start_local_active_span]{start_local_active_span()}}. You must end the span by calling \code{\link[=end_span]{end_span()}}. Alternatively you can also end it with \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}} by setting \code{end_on_exit = TRUE}. It is a good idea to end spans created with \code{start_span()} in an \code{\link[base:on.exit]{base::on.exit()}} call. } \examples{ 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() } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} otel/man/zci.Rd0000644000176200001440000000367715046400601013055 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{Zero Code Instrumentation} \alias{Zero Code Instrumentation} \alias{OTEL_R_INSTRUMENT_PKGS} \title{Zero Code Instrumentation} \value{ Not applicable. } \description{ otel supports zero-code instrumentation (ZCI) via the \code{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 \code{\link[base:trace]{base::trace()}} to produce OpenTelemetry output from every function of these packages. } \details{ By default all functions of the listed packages are instrumented. To instrument a subset of all functions set the \verb{OTEL_INSTRUMENT_R_PKGS__INCLUDE} environment variable to a list of glob expressions. \verb{} 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 \verb{OTEL_INSTRUMENT_R_PKGS__EXCLUDE} environment variable to a list of glob expressions. \verb{} 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. \subsection{Caveats}{ If the user calls \code{\link[base:trace]{base::trace()}} on an instrumented function, that deletes the instrumentation, since the second \code{\link[base:trace]{base::trace()}} call overwrites the first. } } \examples{ # To run an R script with ZCI: # OTEL_TRACES_EXPORTER=http OTEL_INSTRUMENT_R_PKGS=dplyr,tidyr R -q -f script.R } \seealso{ \link{Environment Variables} Other OpenTelemetry trace API: \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} otel/man/otel_histogram.Rd0000644000176200001440000000357015046400601015300 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_histogram} \alias{otel_histogram} \title{OpenTelemetry Histogram Object} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ Usually you do not need to deal with otel_histogram objects directly. \code{\link[=histogram_record]{histogram_record()}} automatically sets up a meter and creates a histogram instrument, as needed. A histogram object is created by calling the \code{create_histogram()} method of an \code{\link[=otel_meter_provider]{otel_meter_provider()}}. You can use the \code{record()} method to update the statistics with the specified amount. In R histogram values are represented by doubles. } \section{Methods}{ \subsection{\code{histogram$record()}}{ Update the statistics with the specified amount. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{histogram$record(value, attributes = NULL, span_context = NULL, ...) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{value}: A numeric value to record. \item \code{attributes}: Additional attributes to add. \item \code{span_context}: Span context. If missing, the active context is used, if any. } } \subsection{Value}{ The histogram object itself, invisibly. } } } \examples{ mp <- get_default_meter_provider() mtr <- mp$get_meter() hst <- mtr$create_histogram("response-time") hst$record(1.123) } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/as_attributes.Rd0000644000176200001440000000311415046400601015123 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/as-attributes.R \name{as_attributes} \alias{as_attributes} \alias{OTEL_ATTRIBUTE_COUNT_LIMIT} \alias{OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT} \title{R objects as OpenTelemetry attributes} \usage{ as_attributes(x) } \arguments{ \item{x}{A list of R objects, to be used as OpenTelemetry attributes.} } \value{ A named list that can be used as the \code{attributes} argument to the \code{start_span()} method of \link{otel_tracer}, the \code{log()} method of \link{otel_logger}, etc. If \code{x} is not named, or some names are the empty string or \code{NA}, then integer numbers as used for the missing or invalid names. If some elements in \code{x} are not of the natively supported R types in OpenTelemetry (character, logical, double, integer), then their printed form is captured using \code{\link[utils:capture.output]{utils::capture.output()}}. \subsection{Limits}{ 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 \code{Inf}. Note that this is applied to the length of each attribute as an R vector. E.g. it does \emph{not} currently limit the number of characters in individual strings. } } \description{ Convert a list of R objects to a form that is suitable as OpenTelemetry attributes. } \examples{ as_attributes(list( number = 1.0, vector = 1:10, string = "otel", string_vector = letters, object = mtcars )) } otel/man/otel_logger.Rd0000644000176200001440000001166515053314630014572 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logger-provider-noop.R \name{otel_logger} \alias{otel_logger} \title{OpenTelemetry Logger Object} \value{ Not applicable. } \description{ \link{otel_logger_provider} -> \link{otel_logger} } \details{ Usually you do not need to deal with otel_logger objects directly. \code{\link[=log]{log()}} automatically sets up the logger for emitting the logs. A logger object is created by calling the \code{get_logger()} method of an \link{otel_logger_provider}. You can use the \code{log()} method of the logger object to emit logs. Typically there is a separate logger object for each instrumented R package. } \section{Methods}{ \subsection{\code{logger$is_enabled()}}{ Whether the logger is active and emitting logs at a certain severity level. This is equivalent to the \code{\link[=is_logging_enabled]{is_logging_enabled()}} function. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{logger$is_enabled(severity = "info", event_id = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{severity}: Check if logs are emitted at this severity level. \item \code{event_id}: Not implemented yet. } } \subsection{Value}{ Logical scalar. } } \subsection{\code{logger$get_minimum_severity()}}{ Get the current minimum severity at which the logger is emitting logs. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{logger_get_minimum_severity() }\if{html}{\out{
}} } \subsection{Value}{ Named integer scalar. } } \subsection{\code{logger$set_minimum_severiry()}}{ Set the minimum severity for emitting logs. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{logger$set_minimum_severity(minimum_severity) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{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". } } \subsection{Value}{ Nothing. } } \subsection{\code{logger$log()}}{ Log an OpenTelemetry log message. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{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() ) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{msg}: Log message, may contain R expressions to evaluate within braces. \item \code{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". \item \code{span_context}: An \link{otel_span_context} object to associate the log message with a span. \item \code{span_id}: Alternatively to \code{span_context}, you can also specify \code{span_id}, \code{trace_id} and \code{trace_flags} to associate a log message with a span. \item \code{trace_id}: Alternatively to \code{span_context}, you can also specify \code{span_id}, \code{trace_id} and \code{trace_flags} to associate a log message with a span. \item \code{trace_flags}: Alternatively to \code{span_context}, you can also specify \code{span_id}, \code{trace_id} and \code{trace_flags} to associate a log message with a span. \item \code{timestamp}: Time stamp, defaults to the current time. This is the time the logged event occurred. \item \code{observed_timestamp}: Observed time stamp, this is the time the event was observed. \item \code{attributes}: Optional attributes, see \code{\link[=as_attributes]{as_attributes()}} for the possible values. } } \subsection{Value}{ The logger object, invisibly. } } \subsection{\code{logger$trace()}}{ The same as \code{logger$log()}, with \code{severity = "trace"}. } \subsection{\code{logger$debug()}}{ The same as \code{logger$log()}, with \code{severity = "debug"}. } \subsection{\code{logger$info()}}{ The same as \code{logger$log()}, with \code{severity = "info"}. } \subsection{\code{logger$warn()}}{ The same as \code{logger$log()}, with \code{severity = "warn"}. } \subsection{\code{logger$error()}}{ The same as \code{logger$log()}, with \code{severity = "error"}. } \subsection{\code{logger$fatal()}}{ The same as \code{logger$log()}, with \code{severity = "fatal"}. } } \examples{ lp <- get_default_logger_provider() lgr <- lp$get_logger() platform <- utils::sessionInfo()$platform lgr$log("This is a log message from {platform}.", severity = "trace") } \seealso{ Other low level logs API: \code{\link{get_default_logger_provider}()}, \code{\link{get_logger}()}, \code{\link{logger_provider_noop}}, \code{\link{otel_logger_provider}} } \concept{low level logs API} otel/man/otel_meter_provider.Rd0000644000176200001440000000754515046400601016337 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_meter_provider} \alias{otel_meter_provider} \title{OpenTelemetry meter provider objects} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ 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 \code{\link[=counter_add]{counter_add()}}, \code{\link[=up_down_counter_add]{up_down_counter_add()}}, \code{\link[=histogram_record]{histogram_record()}}, \code{\link[=gauge_record]{gauge_record()}} or \code{\link[=get_meter]{get_meter()}} call. otel decides which meter provider class to use based on \link{Environment Variables}. } \section{Implementations}{ Note that this list is updated manually and may be incomplete. \itemize{ \item \link{meter_provider_noop}: No-op meter provider, used when no metrics are emitted. \item \link[otelsdk:meter_provider_file]{otelsdk::meter_provider_file}: Save metrics to a JSONL file. \item \link[otelsdk:meter_provider_http]{otelsdk::meter_provider_http}: Send metrics to a collector over HTTP/OTLP. \item \link[otelsdk:meter_provider_memory]{otelsdk::meter_provider_memory}: Collect emitted metrics in memory. For testing. \item \link[otelsdk:meter_provider_stdstream]{otelsdk::meter_provider_stdstream}: Write metrics to standard output or error or to a file. Primarily for debugging. } } \section{Methods}{ \subsection{\code{meter_provider$get_meter()}}{ Get or create a new meter object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{meter_provider$get_meter( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Meter name, see \code{\link[=get_meter]{get_meter()}}. \item \code{version}: Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}. \item \code{schema_url}: Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. \item \code{attributes}: Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. See \code{\link[=as_attributes]{as_attributes()}} for allowed values. You can also use \code{\link[=as_attributes]{as_attributes()}} to convert R objects to OpenTelemetry attributes. } } \subsection{Value}{ Returns an OpenTelemetry meter (\link{otel_meter}) object. } \subsection{See also}{ \code{\link[=get_default_meter_provider]{get_default_meter_provider()}}, \code{\link[=get_meter]{get_meter()}}. } } \subsection{\code{meter_provider$flush()}}{ Force any buffered metrics to flush. Meter providers might not implement this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{meter_provider$flush() }\if{html}{\out{
}} } \subsection{Value}{ Nothing. } } \subsection{\code{meter_provider$shutdown()}}{ Stop the meter provider. Stops collecting and emitting measurements. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{meter_provider$shurdown() }\if{html}{\out{
}} } \subsection{Value}{ Nothing } } } \examples{ mp <- otel::get_default_meter_provider() mtr <- mp$get_meter() mtr$is_enabled() } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/local_active_span.Rd0000644000176200001440000000405115046400601015721 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{local_active_span} \alias{local_active_span} \title{Activate an OpenTelemetry span for an R scope} \usage{ local_active_span(span, end_on_exit = FALSE, activation_scope = parent.frame()) } \arguments{ \item{span}{The OpenTelemetry span to activate.} \item{end_on_exit}{Whether to end the span when exiting the activation scope.} \item{activation_scope}{The scope to activate the span for, defaults to the caller frame.} } \value{ Nothing. } \description{ Activates the span for the caller (or other) frame. Usually you need this function for spans created with \code{\link[=start_span]{start_span()}}, which does not activate the new span. Usually you don't need it for spans created with \code{\link[=start_local_active_span]{start_local_active_span()}}, because it activates the new span automatically. } \details{ 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. } \examples{ 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() } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} Other tracing for concurrent code: \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} \concept{tracing for concurrent code} otel/man/get_active_span_context.Rd0000644000176200001440000000161315046400601017153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{get_active_span_context} \alias{get_active_span_context} \title{Returns the active span context} \usage{ get_active_span_context() } \value{ The active span context, an \link{otel_span_context} object. If there is no active span context, then an invalid span context is returned, i.e. \code{spc$is_valid()} will be \code{FALSE} for the returned \code{spc}. } \description{ This is sometimes useful for logs or metrics, to associate logging and metrics reporting with traces. } \details{ Note that logs and metrics instruments automatically use the current span context, so often you don't need to call this function explicitly. } \examples{ fun <- function() { otel::start_local_active_span("fun") fun2() } fun2 <- function() { otel::log("Log message", span_context = otel::get_active_span_context()) } fun() } otel/man/meter_provider_noop.Rd0000644000176200001440000000144215046400601016335 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \docType{data} \name{meter_provider_noop} \alias{meter_provider_noop} \title{No-op Meter Provider} \value{ Not applicable. } \description{ This is the meter provider (\link{otel_meter_provider}) otel uses when metrics collection is disabled. } \details{ All methods are no-ops or return objects that are also no-ops. } \examples{ meter_provider_noop$new() } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} \keyword{datasets} otel/man/logger_provider_noop.Rd0000644000176200001440000000124415046400601016500 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logger-provider-noop.R \docType{data} \name{logger_provider_noop} \alias{logger_provider_noop} \title{No-op logger provider} \value{ Not applicable. } \description{ This is the logger provider (\link{otel_logger_provider}) otel uses when logging is disabled. } \details{ All methods are no-ops or return objects that are also no-ops. } \examples{ logger_provider_noop$new() } \seealso{ Other low level logs API: \code{\link{get_default_logger_provider}()}, \code{\link{get_logger}()}, \code{\link{otel_logger}}, \code{\link{otel_logger_provider}} } \concept{low level logs API} \keyword{internal} otel/man/gauge_record.Rd0000644000176200001440000000221515046400601014701 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{gauge_record} \alias{gauge_record} \title{Record a value of an OpenTelemetry gauge} \usage{ gauge_record(name, value, attributes = NULL, context = NULL, meter = NULL) } \arguments{ \item{name}{Name of the gauge} \item{value}{Value to record.} \item{attributes}{Additional attributes to add.} \item{context}{Span context. If missing the active context is used, if any.} \item{meter}{Meter object (\link{otel_meter}). Otherwise it is passed to \code{\link[=get_meter]{get_meter()}} to get a meter.} } \value{ The gauge object (\link{otel_gauge}), invisibly. } \description{ Record a value of an OpenTelemetry gauge } \examples{ otel::gauge_record("temperature", 27) } \seealso{ Other OpenTelemetry metrics instruments: \code{\link{counter_add}()}, \code{\link{histogram_record}()}, \code{\link{up_down_counter_add}()} Other OpenTelemetry metrics API: \code{\link{counter_add}()}, \code{\link{histogram_record}()}, \code{\link{is_measuring_enabled}()}, \code{\link{up_down_counter_add}()} } \concept{OpenTelemetry metrics API} \concept{OpenTelemetry metrics instruments} otel/man/pack_http_context.Rd0000644000176200001440000000121015046400601015766 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{pack_http_context} \alias{pack_http_context} \title{Pack the currently active span context into standard HTTP OpenTelemetry headers} \usage{ pack_http_context() } \value{ A named character vector, with lowercase names. It might be an empty vector, e.g. if tracing is disabled. } \description{ The returned headers can be sent over HTTP, or set as environment variables for subprocesses. } \examples{ hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid() } \seealso{ \code{\link[=extract_http_context]{extract_http_context()}} } otel/man/otel_tracer_provider.Rd0000644000176200001440000000657315046400601016503 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-provider-noop.R \name{otel_tracer_provider} \alias{otel_tracer_provider} \title{OpenTelemetry Tracer Provider Object} \value{ Not applicable. } \description{ \link{otel_tracer_provider} -> \link{otel_tracer} -> \link{otel_span} -> \link{otel_span_context} } \details{ 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 \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=start_span]{start_span()}} call. otel decides which tracer provider class to use based on \link{Environment Variables}. } \section{Implementations}{ Note that this list is updated manually and may be incomplete. \itemize{ \item \link{tracer_provider_noop}: No-op tracer provider, used when no traces are emitted. \item \link[otelsdk:tracer_provider_file]{otelsdk::tracer_provider_file}: Save traces to a JSONL file. \item \link[otelsdk:tracer_provider_http]{otelsdk::tracer_provider_http}: Send traces to a collector over HTTP/OTLP. \item \link[otelsdk:tracer_provider_memory]{otelsdk::tracer_provider_memory}: Collect emitted traces in memory. For testing. \item \link[otelsdk:tracer_provider_stdstream]{otelsdk::tracer_provider_stdstream}: Write traces to standard output or error or to a file. Primarily for debugging. } } \section{Methods}{ \subsection{\code{tracer_provider$get_tracer()}}{ Get or create a new tracer object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{tracer_provider$get_tracer( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Tracer name, see \code{\link[=get_tracer]{get_tracer()}}. \item \code{version}: Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}. \item \code{schema_url}: Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. \item \code{attributes}: Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. See \code{\link[=as_attributes]{as_attributes()}} for allowed values. You can also use \code{\link[=as_attributes]{as_attributes()}} to convert R objects to OpenTelemetry attributes. } } \subsection{Value}{ Returns an OpenTelemetry tracer (\link{otel_tracer}) object. } \subsection{See also}{ \code{\link[=get_default_tracer_provider]{get_default_tracer_provider()}}, \code{\link[=get_tracer]{get_tracer()}}. } } \subsection{\code{tracer_provider$flush()}}{ Force any buffered spans to flush. Tracer providers might not implement this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{tracer_provider$flush() }\if{html}{\out{
}} } \subsection{Value}{ Nothing. } } } \examples{ tp <- otel::get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{get_tracer}()}, \code{\link{otel_span}}, \code{\link{otel_span_context}}, \code{\link{otel_tracer}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/otel_counter.Rd0000644000176200001440000000347715046400601014770 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_counter} \alias{otel_counter} \title{OpenTelemetry Counter Object} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ Usually you do not need to deal with otel_counter objects directly. \code{\link[=counter_add]{counter_add()}} automatically sets up a meter and creates a counter instrument, as needed. A counter object is created by calling the \code{create_counter()} method of an \code{\link[=otel_meter_provider]{otel_meter_provider()}}. You can use the \code{add()} method to increment the counter by a positive amount. In R counters are represented by double values. } \section{Methods}{ \subsection{\code{counter$add()}}{ Increment the counter by a fixed amount. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{counter$add(value, attributes = NULL, span_context = NULL, ...) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{value}: Value to increment the counter with. \item \code{attributes}: Additional attributes to add. \item \code{span_context}: Span context. If missing, the active context is used, if any. } } \subsection{Value}{ The counter object itself, invisibly. } } } \examples{ mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1) } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/default_tracer_name.Rd0000644000176200001440000000773315051542704016260 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-name.R \name{default_tracer_name} \alias{default_tracer_name} \alias{otel_tracer_name} \title{Default tracer name (and meter and logger name) for an R package} \usage{ default_tracer_name(name = NULL) } \arguments{ \item{name}{Custom tracer name. If \code{NULL} then otel will construct a a tracer (meter, logger) name according to the algorithm detailed below.} } \value{ A list with entries: \itemize{ \item \code{name}: The supplied or auto-detected tracer name. \item \code{package}: Auto-detected package name or \code{NA}. \item \code{on}: Whether tracing is enabled for this package. } } \description{ 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. } \details{ \subsection{About tracer names}{ 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 '\link{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. } \subsection{Setting the tracer name}{ As a package author, you can define the \code{otel_tracer_name} symbol in your package and set it do the desired tracer name. For example, the callr package has this in an \code{.R} file: \if{html}{\out{
}}\preformatted{otel_tracer_name <- "org.r-lib.callr" }\if{html}{\out{
}} See below for tips on choosing a tracer name. If you don't like the default tracer name, you can call \code{\link[=get_tracer]{get_tracer()}} (or \code{\link[=get_logger]{get_logger()}} or \code{\link[=get_meter]{get_meter()}} manually with the desired name. } \subsection{Automatic tracer name detection in otel}{ This is the detailed algorithm that otel uses in \code{default_tracer_name}: \itemize{ \item Using \code{\link[base:ns-topenv]{base::topenv()}} it finds the calling package (or other top level environment), recursively. \item It ignores the otel and otelsdk packages while searching. \item If it finds the base environment or the global environment, then it checks for the \code{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 \code{org.project.R} is used as the tracer name. \item Otherwise it looks for the \code{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. \item If this symbol does not exist, then otel will use \verb{r.package.} as the tracer name. \verb{} is usually the package name. } } \subsection{Choosing a tracer name}{ The \href{https://opentelemetry.io/docs/specs/otel/trace/api/#get-a-tracer}{OpenTelemetry specification} recommends using a tracer name that identifies the instrumentation scope, i.e. your package. Some tips on choosing the tracer name: \itemize{ \item 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 \code{org.r-lib.callr}. \item 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, \code{co.posit.r-package.shiny} seems like a good name. \item If you don't set \code{otel_tracer_name}, then \code{default_tracer_name} will use \verb{r.package.} as the tracer name. } } } \examples{ default_tracer_name() } otel/man/tracer_provider_noop.Rd0000644000176200001440000000134015046400601016476 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-provider-noop.R \docType{data} \name{tracer_provider_noop} \alias{tracer_provider_noop} \title{No-op tracer provider} \value{ Not applicable. } \description{ This is the tracer provider (\link{otel_tracer_provider}) otel uses when tracing is disabled. } \details{ All methods are no-ops or return objects that are also no-ops. } \examples{ tracer_provider_noop$new() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{get_tracer}()}, \code{\link{otel_span}}, \code{\link{otel_span_context}}, \code{\link{otel_tracer}}, \code{\link{otel_tracer_provider}} } \concept{low level trace API} \keyword{datasets} otel/man/is_logging_enabled.Rd0000644000176200001440000000211115046400601016041 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{is_logging_enabled} \alias{is_logging_enabled} \title{Check whether OpenTelemetry logging is active} \usage{ is_logging_enabled(severity = "info", logger = NULL) } \arguments{ \item{severity}{Check if logs are emitted at this severity level.} \item{logger}{Logger object (\link{otel_logger}), or a logger name, the instrumentation scope, to pass to \code{\link[=get_logger]{get_logger()}}.} } \value{ \code{TRUE} is OpenTelemetry logging is active, \code{FALSE} otherwise. } \description{ This is useful for avoiding computation when logging is inactive. } \details{ It calls \code{\link[=get_logger]{get_logger()}} with \code{name} and then it calls the logger's \verb{$is_enabled()} method. } \examples{ fun <- function() { if (otel::is_logging_enabled()) { xattr <- calculate_some_extra_attributes() otel::log("Starting fun", attributes = xattr) } # ... } } \seealso{ Other OpenTelemetry logs API: \code{\link{log}()}, \code{\link{log_severity_levels}} } \concept{OpenTelemetry logs API} otel/man/otel_meter.Rd0000644000176200001440000001200615046400601014411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_meter} \alias{otel_meter} \title{OpenTelemetry Meter Object} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ Usually you do not need to deal with otel_meter objects directly. \code{\link[=counter_add]{counter_add()}}, \code{\link[=up_down_counter_add]{up_down_counter_add()}}, \code{\link[=histogram_record]{histogram_record()}} and \code{\link[=gauge_record]{gauge_record()}} automatically set up the meter and uses it to create instruments. A meter object is created by calling the \code{get_meter()} method of an \link{otel_meter_provider}. You can use the \code{create_counter()}, \code{create_up_down_counter()}, \code{create_histogram()}, \code{create_gauge()} methods of the meter object to create instruments. Typically there is a separate meter object for each instrumented R package. } \section{Methods}{ \subsection{\code{meter$is_enabled()}}{ Whether the meter is active and emitting measurements. This is equivalent to the \code{\link[=is_measuring_enabled]{is_measuring_enabled()}} function. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{meter$is_enabled() }\if{html}{\out{
}} } \subsection{Value}{ Logical scalar. } } \subsection{\code{meter$create_counter()}}{ Create a new \href{https://opentelemetry.io/docs/specs/otel/metrics/api/#counter}{counter instrument}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{create_counter(name, description = NULL, unit = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Name of the instrument. \item \code{description}: Optional description. \item \code{unit}: Optional measurement unit. If specified, it should use units from \href{https://ucum.org/}{Unified Code for Units of Measure}, according to the \href{https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units}{OpenTelemetry semantic conventions}. } } \subsection{Value}{ An OpenTelemetry counter (\link{otel_counter}) object. } } \subsection{\code{meter$create_up_down_counter()}}{ Create a new \href{https://opentelemetry.io/docs/specs/otel/metrics/api/#updowncounter}{up-down counter instrument}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{create_up_down_counter(name, description = NULL, unit = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Name of the instrument. \item \code{description}: Optional description. \item \code{unit}: Optional measurement unit. If specified, it should use units from \href{https://ucum.org/}{Unified Code for Units of Measure}, according to the \href{https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units}{OpenTelemetry semantic conventions}. } } \subsection{Value}{ An OpenTelemetry counter (\link{otel_up_down_counter}) object. } } \subsection{\code{meter$create_histogram()}}{ Create a new \href{https://opentelemetry.io/docs/specs/otel/metrics/api/#histogram}{histogram}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{create_histogram(name, description = NULL, unit = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Name of the instrument. \item \code{description}: Optional description. \item \code{unit}: Optional measurement unit. If specified, it should use units from \href{https://ucum.org/}{Unified Code for Units of Measure}, according to the \href{https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units}{OpenTelemetry semantic conventions}. } } \subsection{Value}{ An OpenTelemetry histogram (\link{otel_histogram}) object. } } \subsection{\code{meter$create_gauge()}}{ Create a new \href{https://opentelemetry.io/docs/specs/otel/metrics/api/#gauge}{gauge}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{create_gauge(name, description = NULL, unit = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Name of the instrument. \item \code{description}: Optional description. \item \code{unit}: Optional measurement unit. If specified, it should use units from \href{https://ucum.org/}{Unified Code for Units of Measure}, according to the \href{https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units}{OpenTelemetry semantic conventions}. } } \subsection{Value}{ An OpenTelemetry gauge (\link{otel_gauge}) object. } } } \examples{ mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_counter("session") ctr$add(1) } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/log_severity_levels.Rd0000644000176200001440000000115415046400601016341 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \docType{data} \name{log_severity_levels} \alias{log_severity_levels} \title{OpenTelemetry log severity levels} \value{ Not applicable. } \description{ 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. } \examples{ log_severity_levels } \seealso{ Other OpenTelemetry logs API: \code{\link{is_logging_enabled}()}, \code{\link{log}()} } \concept{OpenTelemetry logs API} \keyword{datasets} otel/man/log.Rd0000644000176200001440000000361415053315133013043 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{log} \alias{log} \alias{log_trace} \alias{log_debug} \alias{log_info} \alias{log_warn} \alias{log_error} \alias{log_fatal} \title{Log an OpenTelemetry log message} \usage{ 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) } \arguments{ \item{msg}{Log message.} \item{...}{Additional arguments are passed to the \verb{$log()} method of the logger.} \item{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".} \item{logger}{Logger to use. If not an OpenTelemetry logger object (\link{otel_logger}), then it passed to \code{\link[=get_logger]{get_logger()}} to get a logger.} } \value{ The logger, invisibly. } \description{ Log an OpenTelemetry log message } \details{ \code{log_trace()} is the same as \code{log()} with \code{severity_level} "trace". \code{log_debug()} is the same as \code{log()} with \code{severity_level} "debug". \code{log_info()} is the same as \code{log()} with \code{severity_level} "info". \code{log_warn()} is the same as \code{log()} with \code{severity_level} "warn". \verb{log_error)} is the same as \code{log()} with \code{severity_level} "error". \code{log_fatal()} is the same as \code{log()} with \code{severity_level} "fatal". } \examples{ host <- "my.db.host" port <- 6667 otel::log("Connecting to database at {host}:{port}") } \seealso{ Other OpenTelemetry logs API: \code{\link{is_logging_enabled}()}, \code{\link{log_severity_levels}} } \concept{OpenTelemetry logs API} otel/man/get_default_meter_provider.Rd0000644000176200001440000000452415046400601017651 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/defaults.R \name{get_default_meter_provider} \alias{get_default_meter_provider} \alias{setup_default_meter_provider} \title{Get the default meter provider} \usage{ get_default_meter_provider() } \value{ The default meter provider, an \link{otel_meter_provider} object. } \description{ 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. } \details{ 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: \itemize{ \item \code{none}: no metrics are exported. \item \code{stdout} or \code{console}: uses \link[otelsdk:meter_provider_stdstream]{otelsdk::meter_provider_stdstream}, to write metrics to the standard output. \item \code{stderr}: uses \link[otelsdk:meter_provider_stdstream]{otelsdk::meter_provider_stdstream}, to write metrics to the standard error. \item \code{http} or \code{otlp}: uses \link[otelsdk:meter_provider_http]{otelsdk::meter_provider_http}, to send metrics through HTTP, using the OpenTelemetry Protocol (OTLP). \item \code{otlp/file} uses \link[otelsdk:meter_provider_file]{otelsdk::meter_provider_file} to write metrics to a JSONL file. \item \verb{::}: will select the \verb{} object from the \verb{} package to use as a meter provider. It calls \verb{::$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. } } \examples{ get_default_meter_provider() } \seealso{ Other low level metrics API: \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/get_default_logger_provider.Rd0000644000176200001440000000433615046400601020015 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/defaults.R \name{get_default_logger_provider} \alias{get_default_logger_provider} \alias{setup_default_logger_provider} \title{Get the default logger provider} \usage{ get_default_logger_provider() } \value{ The default logger provider, an \link{otel_logger_provider} object. } \description{ 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. } \details{ 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: \itemize{ \item \code{none}: no traces are exported. \item \code{stdout} or \code{console}: uses \link[otelsdk:logger_provider_stdstream]{otelsdk::logger_provider_stdstream}, to write traces to the standard output. \item \code{stderr}: uses \link[otelsdk:logger_provider_stdstream]{otelsdk::logger_provider_stdstream}, to write traces to the standard error. \item \code{http} or \code{otlp}: uses \link[otelsdk:logger_provider_http]{otelsdk::logger_provider_http}, to send traces through HTTP, using the OpenTelemetry Protocol (OTLP). \item \code{otlp/file} uses \link[otelsdk:logger_provider_file]{otelsdk::logger_provider_file} to write logs to a JSONL file. \item \verb{::}: will select the \verb{} object from the \verb{} package to use as a logger provider. It calls \verb{::$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. } } \examples{ get_default_logger_provider() } \seealso{ Other low level logs API: \code{\link{get_logger}()}, \code{\link{logger_provider_noop}}, \code{\link{otel_logger}}, \code{\link{otel_logger_provider}} } \concept{low level logs API} otel/man/get_tracer.Rd0000644000176200001440000000456015046400601014377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{get_tracer} \alias{get_tracer} \title{Get a tracer from the default tracer provider} \usage{ get_tracer( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) } \arguments{ \item{name}{Name of the new tracer. If missing, then deduced automatically using \code{\link[=default_tracer_name]{default_tracer_name()}}. Make sure you read the manual page of \code{\link[=default_tracer_name]{default_tracer_name()}} before using this argument.} \item{version}{Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}.} \item{schema_url}{Optional. Specifies the Schema URL that should be recorded in the emitted telemetry.} \item{attributes}{Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry.} \item{...}{Additional arguments are passed to the \code{get_tracer()} method of the provider.} \item{provider}{Tracer provider to use. If \code{NULL}, then it uses \code{\link[=get_default_tracer_provider]{get_default_tracer_provider()}} to get a tracer provider.} } \value{ An OpenTelemetry tracer, an \link{otel_tracer} object. } \description{ Calls \code{\link[=get_default_tracer_provider]{get_default_tracer_provider()}} to get the default tracer provider. Then calls its \verb{$get_tracer()} method to create a new tracer. } \details{ Usually you do not need to call this function directly, because \code{\link[=start_local_active_span]{start_local_active_span()}} calls it for you. Calling \code{get_tracer()} multiple times with the same \code{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. } \examples{ 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() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{otel_span}}, \code{\link{otel_span_context}}, \code{\link{otel_tracer}}, \code{\link{otel_tracer_provider}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/get_active_span.Rd0000644000176200001440000000110215051666774015425 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{get_active_span} \alias{get_active_span} \title{Returns the active span, if any} \usage{ get_active_span() } \value{ The active span, an \link{otel_span} object, if any, or an invalid span if there is no active span. } \description{ This is sometimes useful, to add additional attributes or links to the currently active span. } \examples{ fun <- function() { otel::start_local_active_span("fun") spn <- otel::get_active_span() spn$set_attribute("key", "attribute-value") } fun() } otel/man/otel_logger_provider.Rd0000644000176200001440000000624115046400601016472 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logger-provider-noop.R \name{otel_logger_provider} \alias{otel_logger_provider} \title{OpenTelemetry Logger Provider Object} \value{ Not applicable. } \description{ \link{otel_logger_provider} -> \link{otel_logger} } \details{ 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 \code{\link[=log]{log()}} call. otel decides which logger provider class to use based on \link{Environment Variables}. } \section{Implementations}{ Note that this list is updated manually and may be incomplete. \itemize{ \item \link{logger_provider_noop}: No-op logger provider, used when no logs are emitted. \item \link[otelsdk:logger_provider_file]{otelsdk::logger_provider_file}: Save logs to a JSONL file. \item \link[otelsdk:logger_provider_http]{otelsdk::logger_provider_http}: Send logs to a collector over HTTP/OTLP. \item \link[otelsdk:logger_provider_stdstream]{otelsdk::logger_provider_stdstream}: Write logs to standard output or error or to a file. Primarily for debugging. } } \section{Methods}{ \subsection{\code{logger_provider$get_logger()}}{ Get or create a new logger object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{logger_provider$get_logger( name = NULL, version = NULL, schema_url = NULL, attributes = NULL ) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name} Logger name. It makes sense to reuse the tracer name as the logger name. See \code{\link[=get_logger]{get_logger()}} and \code{\link[=default_tracer_name]{default_tracer_name()}}. \item \code{version}: Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}. \item \code{schema_url}: Optional. Specifies the Schema URL that should be recorded in the emitted telemetry. \item \code{attributes}: Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry. See \code{\link[=as_attributes]{as_attributes()}} for allowed values. You can also use \code{\link[=as_attributes]{as_attributes()}} to convert R objects to OpenTelemetry attributes. } } \subsection{Value}{ An OpenTelemetry logger (\link{otel_logger}) object. } \subsection{See also}{ \code{\link[=get_default_logger_provider]{get_default_logger_provider()}}, \code{\link[=get_logger]{get_logger()}}. } } \subsection{\code{logger_provider$flush()}}{ Force any buffered logs to flush. Logger providers might not implement this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{logger_provider$flush() }\if{html}{\out{
}} } \subsection{Value}{ Nothing. } } } \examples{ lp <- otel::get_default_logger_provider() lgr <- lp$get_logger() lgr$is_enabled() } \seealso{ Other low level logs API: \code{\link{get_default_logger_provider}()}, \code{\link{get_logger}()}, \code{\link{logger_provider_noop}}, \code{\link{otel_logger}} } \concept{low level logs API} otel/man/end_span.Rd0000644000176200001440000000272115046400601014044 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{end_span} \alias{end_span} \title{End an OpenTelemetry span} \usage{ end_span(span) } \arguments{ \item{span}{The span to end.} } \value{ Nothing. } \description{ Spans created with \code{\link[=start_local_active_span]{start_local_active_span()}} end automatically by default. You must end every other span manually, by calling \code{end_span}, or using the \code{end_on_exit} argument of \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}. } \examples{ 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() } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} otel/man/get_logger.Rd0000644000176200001440000000310515046400601014370 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{get_logger} \alias{get_logger} \title{Get a logger from the default logger provider} \usage{ get_logger( name = NULL, minimum_severity = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) } \arguments{ \item{name}{Name of the new tracer. If missing, then deduced automatically.} \item{minimum_severity}{A log level, the minimum severity log messages to log. See \link{log_severity_levels}.} \item{version}{Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}.} \item{schema_url}{Optional. Specifies the Schema URL that should be recorded in the emitted telemetry.} \item{attributes}{Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry.} \item{...}{Additional arguments are passed to the \code{get_logger()} method of the provider.} \item{provider}{Tracer provider to use. If \code{NULL}, then it uses \code{\link[=get_default_tracer_provider]{get_default_tracer_provider()}} to get a tracer provider.} } \value{ An \link{otel_logger} object. } \description{ Get a logger from the default logger provider } \examples{ myfun <- function() { lgr <- otel::get_logger() otel::log("Log message", logger = lgr) } myfun() } \seealso{ Other low level logs API: \code{\link{get_default_logger_provider}()}, \code{\link{logger_provider_noop}}, \code{\link{otel_logger}}, \code{\link{otel_logger_provider}} } \concept{low level logs API} otel/man/with_active_span.Rd0000644000176200001440000000372515046400601015611 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{with_active_span} \alias{with_active_span} \title{Evaluate R code with an active OpenTelemetry span} \usage{ with_active_span(span, expr, end_on_exit = FALSE) } \arguments{ \item{span}{The OpenTelemetry span to activate.} \item{expr}{R expression to evaluate.} \item{end_on_exit}{Whether to end after evaluating the R expression.} } \value{ The return value of \code{expr}. } \description{ Activates the span for evaluating an R expression. Usually you need this function for spans created with \code{\link[=start_span]{start_span()}}, which does not activate the new span. Usually you don't need it for spans created with \code{\link[=start_local_active_span]{start_local_active_span()}}, because it activates the new span automatically. } \details{ After \code{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. } \examples{ 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() } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}} Other tracing for concurrent code: \code{\link{local_active_span}()} } \concept{OpenTelemetry trace API} \concept{tracing for concurrent code} otel/man/get_meter.Rd0000644000176200001440000000306715046400601014234 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{get_meter} \alias{get_meter} \title{Get a meter from the default meter provider} \usage{ get_meter( name = NULL, version = NULL, schema_url = NULL, attributes = NULL, ..., provider = NULL ) } \arguments{ \item{name}{Name of the new tracer. If missing, then deduced automatically.} \item{version}{Optional. Specifies the version of the instrumentation scope if the scope has a version (e.g. R package version). Example value: \code{"1.0.0"}.} \item{schema_url}{Optional. Specifies the Schema URL that should be recorded in the emitted telemetry.} \item{attributes}{Optional. Specifies the instrumentation scope attributes to associate with emitted telemetry.} \item{...}{Additional arguments are passed to the \code{get_meter()} method of the provider.} \item{provider}{Meter provider to use. If \code{NULL}, then it uses \code{\link[=get_default_meter_provider]{get_default_meter_provider()}} to get a tracer provider.} } \value{ An \link{otel_meter} object. } \description{ Get a meter from the default meter provider } \examples{ myfun <- function() { mtr <- otel::get_meter() ctr <- mtr$create_counter("session-count") ctr$add(1) } myfun() } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/up_down_counter_add.Rd0000644000176200001440000000242215046400601016275 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{up_down_counter_add} \alias{up_down_counter_add} \title{Increase or decrease an OpenTelemetry up-down counter} \usage{ up_down_counter_add( name, value = 1L, attributes = NULL, context = NULL, meter = NULL ) } \arguments{ \item{name}{Name of the up-down counter.} \item{value}{Value to add to or subtract from the counter, defaults to 1.} \item{attributes}{Additional attributes to add.} \item{context}{Span context. If missing the active context is used, if any.} \item{meter}{Meter object (\link{otel_meter}). Otherwise it is passed to \code{\link[=get_meter]{get_meter()}} to get a meter.} } \value{ The up-down counter object (\link{otel_up_down_counter}), invisibly. } \description{ Increase or decrease an OpenTelemetry up-down counter } \examples{ otel::up_down_counter_add("session-count", 1) } \seealso{ Other OpenTelemetry metrics instruments: \code{\link{counter_add}()}, \code{\link{gauge_record}()}, \code{\link{histogram_record}()} Other OpenTelemetry metrics API: \code{\link{counter_add}()}, \code{\link{gauge_record}()}, \code{\link{histogram_record}()}, \code{\link{is_measuring_enabled}()} } \concept{OpenTelemetry metrics API} \concept{OpenTelemetry metrics instruments} otel/man/otel_gauge.Rd0000644000176200001440000000347715046400601014401 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_gauge} \alias{otel_gauge} \title{OpenTelemetry Gauge Object} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ Usually you do not need to deal with otel_gauge objects directly. \code{\link[=gauge_record]{gauge_record()}} automatically sets up a meter and creates a gauge instrument, as needed. A gauge object is created by calling the \code{create_gauge()} method of an \code{\link[=otel_meter_provider]{otel_meter_provider()}}. You can use the \code{record()} method to record the current value. In R gauge values are represented by doubles. } \section{Methods}{ \subsection{\code{gauge$record()}}{ Update the statistics with the specified amount. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{gauge$record(value, attributes = NULL, span_context = NULL, ...) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{value}: A numeric value. The current absolute value. \item \code{attributes}: Additional attributes to add. \item \code{span_context}: Span context. If missing, the active context is used, if any. } } \subsection{Value}{ The gauge object itself, invisibly. } } } \examples{ mp <- get_default_meter_provider() mtr <- mp$get_meter() gge <- mtr$create_gauge("response-time") gge$record(1.123) } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}}, \code{\link{otel_up_down_counter}} } \concept{low level metrics API} otel/man/tracing-constants.Rd0000644000176200001440000000426415046400601015722 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/constants.R \docType{data} \name{tracing-constants} \alias{tracing-constants} \alias{invalid_trace_id} \alias{invalid_span_id} \alias{span_kinds} \alias{span_status_codes} \title{OpenTelemetry tracing constants} \usage{ invalid_trace_id invalid_span_id span_kinds span_status_codes } \value{ Not applicable. } \description{ Various constants related OpenTelemetry tracing. } \details{ \subsection{\code{invalid_trace_id}}{ \code{invalid_trace_id} is a string scalar, an invalid trace id. If there is no active span, then \code{\link[=get_active_span_context]{get_active_span_context()}} returns a span context that has an invalid trace id. } \subsection{\code{invalid_span_id}}{ \code{invalid_span_id} is a string scalar, an invalid span id. If there is no active span, then \code{\link[=get_active_span_context]{get_active_span_context()}} returns a span context that has an invalid span id. } \subsection{\code{span_kinds}}{ \code{span_kinds} is a character vector listing all possible span kinds. See the \href{https://opentelemetry.io/docs/specs/otel/trace/api/#spankind}{OpenTelemetry specification} for when to use which. } \subsection{\code{span_status_codes}}{ \code{span_status_codes} is a character vector listing all possible span status codes. You can set the status code of a a span with the \code{set_status()} method of \link{otel_span} objects. If not set explicitly, and the span is ended automatically (by \code{\link[=start_local_active_span]{start_local_active_span()}}, \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}), then otel sets the status automatically to "ok" or "error", depending on whether the span ended during handling an error. } } \examples{ invalid_trace_id invalid_span_id span_kinds span_status_codes } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} \keyword{datasets} otel/man/counter_add.Rd0000644000176200001440000000225315046400601014544 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{counter_add} \alias{counter_add} \title{Increase an OpenTelemetry counter} \usage{ counter_add(name, value = 1L, attributes = NULL, context = NULL, meter = NULL) } \arguments{ \item{name}{Name of the counter.} \item{value}{Value to add to the counter, defaults to 1.} \item{attributes}{Additional attributes to add.} \item{context}{Span context. If missing the active context is used, if any.} \item{meter}{Meter object (\link{otel_meter}). Otherwise it is passed to \code{\link[=get_meter]{get_meter()}} to get a meter.} } \value{ The counter object (\link{otel_counter}), invisibly. } \description{ Increase an OpenTelemetry counter } \examples{ otel::counter_add("total-session-count", 1) } \seealso{ Other OpenTelemetry metrics instruments: \code{\link{gauge_record}()}, \code{\link{histogram_record}()}, \code{\link{up_down_counter_add}()} Other OpenTelemetry metrics API: \code{\link{gauge_record}()}, \code{\link{histogram_record}()}, \code{\link{is_measuring_enabled}()}, \code{\link{up_down_counter_add}()} } \concept{OpenTelemetry metrics API} \concept{OpenTelemetry metrics instruments} otel/man/otel_up_down_counter.Rd0000644000176200001440000000371315046400601016514 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/meter-provider-noop.R \name{otel_up_down_counter} \alias{otel_up_down_counter} \title{OpenTelemetry Up-Down Counter Object} \value{ Not applicable. } \description{ \link{otel_meter_provider} -> \link{otel_meter} -> \link{otel_counter}, \link{otel_up_down_counter}, \link{otel_histogram}, \link{otel_gauge} } \details{ Usually you do not need to deal with otel_up_down_counter objects directly. \code{\link[=up_down_counter_add]{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 \code{create_up_down_counter()} method of an \code{\link[=otel_meter_provider]{otel_meter_provider()}}. You can use the \code{add()} method to increment or decrement the counter. In R up-down counters are represented by double values. } \section{Methods}{ \subsection{\code{up_down_counter$add()}}{ Increment or decrement the up-down counter by a fixed amount. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{up_down_counter$add(value, attributes = NULL, span_context = NULL, ...) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{value}: Value to increment of decrement the up-down counter with. \item \code{attributes}: Additional attributes to add. \item \code{span_context}: Span context. If missing, the active context is used, if any. } } \subsection{Value}{ The up-down counter object itself, invisibly. } } } \examples{ mp <- get_default_meter_provider() mtr <- mp$get_meter() ctr <- mtr$create_up_down_counter("session") ctr$add(1) } \seealso{ Other low level metrics API: \code{\link{get_default_meter_provider}()}, \code{\link{get_meter}()}, \code{\link{meter_provider_noop}}, \code{\link{otel_counter}}, \code{\link{otel_gauge}}, \code{\link{otel_histogram}}, \code{\link{otel_meter}}, \code{\link{otel_meter_provider}} } \concept{low level metrics API} otel/man/otel_tracer.Rd0000644000176200001440000000654715046400601014572 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-provider-noop.R \name{otel_tracer} \alias{otel_tracer} \title{OpenTelemetry Tracer Object} \value{ Not applicable. } \description{ \link{otel_tracer_provider} -> \link{otel_tracer} -> \link{otel_span} -> \link{otel_span_context} } \details{ Usually you do not need to deal with otel_tracer objects directly. \code{\link[=start_local_active_span]{start_local_active_span()}} (and \code{\link[=start_span]{start_span()}}) automatically sets up the tracer and uses it to create spans. A tracer object is created by calling the \code{get_tracer()} method of an \link{otel_tracer_provider}. You can use the \code{start_span()} method of the tracer object to create a span. Typically there is a separate tracer object for each instrumented R package. } \section{Methods}{ \subsection{\code{tracer$start_span()}}{ Creates and starts a new span. It does not activate the new span. It is equivalent to the \code{\link[=start_span]{start_span()}} function. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{tracer_start_span( name = NULL, attributes = NULL, links = NULL, options = NULL ) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Name of the span. If not specified it will be \code{""}. \item \code{attributes}: Span attributes. OpenTelemetry supports the following R types as attributes: `character, logical, double, integer. You may use \code{\link[=as_attributes]{as_attributes()}} to convert other R types to OpenTelemetry attributes. \item \code{links}: A named list of links to other spans. Every link must be an OpenTelemetry span (\link{otel_span}) object, or a list with a span object as the first element and named span attributes as the rest. \item \code{options}: A named list of span options. May include: \itemize{ \item \code{start_system_time}: Start time in system time. \item \code{start_steady_time}: Start time using a steady clock. \item \code{parent}: A parent span or span context. If it is \code{NA}, then the span has no parent and it will be a root span. If it is \code{NULL}, then the current context is used, i.e. the active span, if any. \item \code{kind}: Span kind, one of \link{span_kinds}: "internal", "server", "client", "producer", "consumer".} } } \subsection{Value}{ A new \link{otel_span} object. } } \subsection{\code{tracer$is_enabled()}}{ Whether the tracer is active and recording traces. This is equivalent to the \code{\link[=is_tracing_enabled]{is_tracing_enabled()}} function. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{tracer$is_enabled() }\if{html}{\out{
}} } \subsection{Value}{ Logical scalar. } } \subsection{\code{tracer$flush()}}{ Flush the tracer provider: force any buffered spans to flush. Tracer providers might not implement this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{tracer$flush() }\if{html}{\out{
}} } \subsection{Value}{ Nothing. } } } \examples{ tp <- get_default_tracer_provider() trc <- tp$get_tracer() trc$is_enabled() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{get_tracer}()}, \code{\link{otel_span}}, \code{\link{otel_span_context}}, \code{\link{otel_tracer_provider}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/extract_http_context.Rd0000644000176200001440000000126615046400601016535 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{extract_http_context} \alias{extract_http_context} \title{Extract a span context from HTTP headers received from a client} \usage{ extract_http_context(headers) } \arguments{ \item{headers}{A named list with one or two strings: \code{traceparent} is mandatory, and \code{tracestate} is optional.} } \value{ And \link{otel_span_context} object. } \description{ The return value can be used as the \code{parent} option when starting a span. } \examples{ hdr <- otel::pack_http_context() ctx <- otel::extract_http_context() ctx$is_valid() } \seealso{ \code{\link[=pack_http_context]{pack_http_context()}} } otel/man/environmentvariables.Rd0000644000176200001440000001400015046400601016503 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{Environment Variables} \alias{Environment Variables} \alias{OTEL_ENV} \alias{OTEL_TRACES_EXPORTER} \alias{OTEL_R_TRACES_EXPORTER} \alias{OTEL_LOGS_EXPORTER} \alias{OTEL_R_LOGS_EXPORTER} \alias{OTEL_METRICS_EXPORTER} \alias{OTEL_R_METRICS_EXPORTER} \alias{OTEL_R_EMIT_SCOPES} \alias{OTEL_R_SUPPRESS_SCOPES} \title{Environment variables to configure otel} \value{ Not applicable. } \description{ This manual page contains the environment variables you can use to configure the otel package. See also the \link[otelsdk:Environment Variables]{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. } \section{Production or Development Environment}{ \itemize{ \item \code{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 \if{html}{\out{
}}\preformatted{OTEL_ENV=dev }\if{html}{\out{
}} to run otel in development mode, where otel functions fail on error, make it easier to fix errors. } } \section{Selecting Exporters}{ 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. \itemize{ \item \code{OTEL_TRACES_EXPORTER} The name of the selected tracer provider. See \code{\link[=get_default_tracer_provider]{get_default_tracer_provider()}} for the possible values. \item \code{OTEL_R_TRACES_EXPORTER} R specific version of \code{OTEL_TRACES_EXPORTER}. \item \code{OTEL_LOGS_EXPORTER} The name of the selected logger provider. See \code{\link[=get_default_logger_provider]{get_default_logger_provider()}} for the possible values. \item \code{OTEL_R_LOGS_EXPORTER} R specific version of \code{OTEL_LOGS_EXPORTER}. \item \code{OTEL_METRICS_EXPORTER} The name of the selected meter provider. See \code{\link[=get_default_meter_provider]{get_default_meter_provider()}} for the possible values. \item \code{OTEL_R_METRICS_EXPORTER} R specific version of \code{OTEL_METRICS_EXPORTER}. } } \section{Suppressing Instrumentation Scopes (R Packages)}{ 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. \itemize{ \item \code{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 \code{\link[=default_tracer_name]{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 \code{org.r-lib.} and also dplyr. \item \code{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 \code{\link[=default_tracer_name]{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 \code{org.r-lib.} and also dplyr. } } \section{\link[=Zero Code Instrumentation]{Zero Code Instrumentation}}{ 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 \code{base::trace()} and can be configured using environment variables. \itemize{ \item \code{OTEL_R_INSTRUMENT_PKGS} Set \code{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. \item \verb{OTEL_R_INSTRUMENT_PKGS__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 \verb{?} and \code{*} wildcards (globbing). \item \verb{OTEL_R_INSTRUMENT_PKGS__EXCLUDE} For an automatically instrumented package, set this environment variable to exclude some functions from instrumentation. It has the same syntax as its \verb{*_INCLUDE} pair. If both are set, then inclusion is applied and the exclusion. } } \section{Attribute Limits}{ \itemize{ \item \code{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 \code{\link[=as_attributes]{as_attributes()}} are subject to this environment variable. \item \code{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 \code{\link[=as_attributes]{as_attributes()}} are subject to this environment variable. } } \examples{ # To start an R session using the OTLP exporter: # OTEL_TRACES_EXPORTER=http R -q -f script.R } \seealso{ \link[otelsdk:Environment Variables]{Environment Variables} in otelsdk } otel/man/gettingstarted.Rd0000644000176200001440000002440215046400601015305 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/docs.R \name{Getting Started} \alias{Getting Started} \alias{gettingstarted} \title{Getting Started} \description{ This page is about instrumenting you R package or project for OpenTelemetry. If you want to start collecting OpenTelemetry data for instrumented packages, see \link[otelsdk:Collecting Telemetry Data]{ Collecting Telemetry Data} in the otelsdk package. } \section{About OpenTelemetry}{ OpenTelemetry is an observability framework. \href{https://opentelemetry.io/}{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 \href{https://opentelemetry.io/docs/}{OpenTelemetry website docs}. } \section{The otel and otelsdk R packages}{ Use the \href{https://github.com/r-lib/otel}{otel} package as a dependency if you want to instrument your R package or project for OpenTelemetry. Use the \href{https://github.com/r-lib/otelsdk}{otelsdk} package to produce OpenTelemetry output from an R package or project that was instrumented with the otel package. } \section{Complete Example}{ To instrument your package with otel, you need to do a couple of steps. In this section we show how to instrument the \href{https://github.com/r-lib/callr}{callr} package. \subsection{Add the otel package as a dependency}{ 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 \code{Imports} section in \code{DESCRIPTION}: \if{html}{\out{
}}\preformatted{Imports: otel }\if{html}{\out{
}} Alternatively, you may add otel as a soft dependency. Add otel to the \code{Suggests} section in \code{DESCRIPTION}: \if{html}{\out{
}}\preformatted{Suggests: otel }\if{html}{\out{
}} If you add otel in \code{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. \code{R/utils.R} is a nice place for it: \if{html}{\out{
}}\preformatted{is_otel_tracing <- function() \{ requireNamespace("otel", quietly = TRUE) && otel::is_tracing_enabled() \} }\if{html}{\out{
}} } \subsection{Choose a tracer name}{ Every package should have its own tracer with a name that is unique for the package. See \code{\link[=default_tracer_name]{default_tracer_name()}} for tips on choosing a good tracer name. Set the \code{otel_tracer_name} variable to the tracer name. No need to export this symbol. In callr, we'll add \if{html}{\out{
}}\preformatted{otel_tracer_name <- "org.r-lib.callr" }\if{html}{\out{
}} to the \code{R/callr-package.R} file. } \subsection{Create spans for selected functions}{ 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 \itemize{ \item \code{callr::r()} \item \code{callr::rcmd()} \item \code{callr::rscript()} } functions first. We add to \code{callr::r()} in \code{eval.R}: \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ otel::start_local_active_span( "callr::r", attributes = otel::as_attributes(options) ) \} }\if{html}{\out{
}} \itemize{ \item We use the \code{is_otel_tracing()} helper function, defined above. \item \code{\link[=start_local_active_span]{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 (\code{callr::r()}) exits. \item \code{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 \code{callr::rcmd()}: \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ otel::start_local_active_span( "callr::rcmd", attributes = otel::as_attributes(options) ) \} }\if{html}{\out{
}} And to \code{callr::rscript()}: \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ otel::start_local_active_span( "callr::rscript", attributes = otel::as_attributes(options) ) \} }\if{html}{\out{
}} } \subsection{Concurrency}{ An instance of the \code{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: \enumerate{ \item Create a new long lasting span with \code{\link[=start_span]{start_span()}}. (I.e. \emph{not} \code{\link[=start_local_active_span]{start_local_active_span()}}!) \item Assign the returned span into the corresponding object of the concurrent and/or asynchronous computation. Every span has a finalizer that closes the span. \item When running code that belongs to the concurrent computation represented by the span, activate it for a specific R scope by calling \code{\link[=with_active_span]{with_active_span()}} or \code{\link[=local_active_span]{local_active_span()}}. \item When the concurrent computation ends, close the span manually with its \verb{$end()} method or \code{\link[=end_span]{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 \code{r_session} object: \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ private$options$otel_session <- otel::start_span( "callr::r_session", attributes = otel::as_attributes(options) ) \} }\if{html}{\out{
}} The \code{finalize()} method (the finalizer) gets a call to close the span: \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ private$options$otel_session$end() \} }\if{html}{\out{
}} We also add (sub)spans to other operations, e.g. the \code{read()} method gets \if{html}{\out{
}}\preformatted{ if (is_otel_tracing()) \{ otel::local_session(private$options$otel_session) spn <- otel::start_local_active_span("callr::r_session$read") \} }\if{html}{\out{
}} } \subsection{Testing}{ To test your instrumentation, you need to install the \href{https://github.com/r-lib/otelsdk}{otelsdk} package and you also need a local or remote OpenTelemetry collector. I suggest you use \href{https://github.com/ymtdzzz/otel-tui}{\code{otel-tui}}, a terminal OpenTelemetry viewer. To configure it, use the \code{http} exporter, see \link{Environment Variables}: \if{html}{\out{
}}\preformatted{OTEL_TRACES_EXPORTER=http R -q }\if{html}{\out{
}} } \subsection{Development mode}{ 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: \if{html}{\out{
}}\preformatted{OTEL_ENV=dev }\if{html}{\out{
}} } \subsection{Context propagation}{ 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 \code{callr:r()} code we may write: \if{html}{\out{
}}\preformatted{ 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 \} }\if{html}{\out{
}} \code{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 \code{\link[=pack_http_context]{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 \code{callr:::common_hook()} internal function contains the code that the subprocess runs at startup. Here we need to add: \if{html}{\out{
}}\preformatted{ 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) ) ) \} }\if{html}{\out{
}} First we check if the \code{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. } } \examples{ # See above } otel/man/get_default_tracer_provider.Rd0000644000176200001440000000452315046400601020014 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/defaults.R \name{get_default_tracer_provider} \alias{get_default_tracer_provider} \alias{setup_default_tracer_provider} \title{Get the default tracer provider} \usage{ get_default_tracer_provider() } \value{ The default tracer provider, an \link{otel_tracer_provider} object. See \link{otel_tracer_provider} for its methods. } \description{ 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. } \details{ 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: \itemize{ \item \code{none}: no traces are exported. \item \code{stdout} or \code{console}: uses \link[otelsdk:tracer_provider_stdstream]{otelsdk::tracer_provider_stdstream}, to write traces to the standard output. \item \code{stderr}: uses \link[otelsdk:tracer_provider_stdstream]{otelsdk::tracer_provider_stdstream}, to write traces to the standard error. \item \code{http} or \code{otlp}: uses \link[otelsdk:tracer_provider_http]{otelsdk::tracer_provider_http}, to send traces through HTTP, using the OpenTelemetry Protocol (OTLP). \item \code{otlp/file} uses \link[otelsdk:tracer_provider_file]{otelsdk::tracer_provider_file} to write traces to a JSONL file. \item \verb{::}: will select the \verb{} object from the \verb{} package to use as a tracer provider. It calls \verb{::$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. } } \examples{ get_default_tracer_provider() } \seealso{ Other low level trace API: \code{\link{get_tracer}()}, \code{\link{otel_span}}, \code{\link{otel_span_context}}, \code{\link{otel_tracer}}, \code{\link{otel_tracer_provider}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/otel_span.Rd0000644000176200001440000002220115046400601014234 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tracer-provider-noop.R \name{otel_span} \alias{otel_span} \title{OpenTelemetry Span Object} \value{ Not applicable. } \description{ \link{otel_tracer_provider} -> \link{otel_tracer} -> \link{otel_span} -> \link{otel_span_context} } \details{ An otel_span object represents an OpenTelemetry span. Use \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=start_span]{start_span()}} to create and start a span. Call \code{\link[=end_span]{end_span()}} to end a span explicitly. (See \code{\link[=start_local_active_span]{start_local_active_span()}} and \code{\link[=local_active_span]{local_active_span()}} to end a span automatically.) } \section{Lifetime}{ The span starts when it is created in the \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=start_span]{start_span()}} call. The span ends when \code{\link[=end_span]{end_span()}} is called on it, explicitly or automatically via \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=local_active_span]{local_active_span()}}. } \section{Activation}{ 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. \subsection{Automatic spans}{ \code{\link[=start_local_active_span]{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. } \subsection{Manual spans}{ \code{\link[=start_span]{start_span()}} creates a new span and starts it, but it does not activate it. You must activate the span manually using \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}. You must also end the span manually with an \code{\link[=end_span]{end_span()}} call. (Or the \code{end_on_exit} argument of \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}.) } } \section{Parent spans}{ 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 \code{parent = NA} in \code{options} to the \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=start_span]{start_span()}} call. } \section{Methods}{ \subsection{\code{span$add_event()}}{ Add a single event to the span. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$add_event(name, attributes = NULL, timestamp = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Event name. \item \code{attributes}: Attributes to add to the event. See \code{\link[=as_attributes]{as_attributes()}} for supported R types. You may also use \code{\link[=as_attributes]{as_attributes()}} to convert an R object to an OpenTelemetry attribute value. \item \code{timestamp}: A \link[base:DateTimeClasses]{base::POSIXct} object. If missing, the current time is used. } } \subsection{Value}{ The span object itself, invisibly. } } \subsection{\code{span$end()}}{ End the span. Calling this method is equivalent to calling the \code{\link[=end_span]{end_span()}} function on the span. Spans created with \code{\link[=start_local_active_span]{start_local_active_span()}} end automatically by default. You must end every other span manually, by calling \code{end_span}, or using the \code{end_on_exit} argument of \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}. Calling the \code{span$end()} method (or \code{end_span()}) on a span multiple times is not an error, the first call ends the span, subsequent calls do nothing. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$end(options = NULL, status_code = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{options}: Named list of options. Possible entry: \itemize{ \item \code{end_steady_time}: A \link[base:DateTimeClasses]{base::POSIXct} object that will be used as a steady timer. } \item \code{status_code}: Span status code to set before ending the span, see the \code{span$set_status()} method for possible values. } } \subsection{Value}{ The span object itself, invisibly. } } \subsection{\code{span$get_context()}}{ Get a span's span context. The span context is an \link{otel_span_context} object that can be serialized, copied to other processes, and it can be used to create new child spans. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$get_context() }\if{html}{\out{
}} } \subsection{Value}{ An \link{otel_span_context} object. } } \subsection{\code{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. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$is_recording() }\if{html}{\out{
}} } \subsection{Value}{ A logical scalar, \code{TRUE} if the span is recorded. } } \subsection{\code{span$record_exception()}}{ Record an exception (error, usually) event for a span. If the span was created with \code{\link[=start_local_active_span]{start_local_active_span()}}, or it was ended automatically with \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{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. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$record_exception(error_condition, attributes, ...) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{error_condition}: An R error object to record. \item \code{attributes}: Additional attributes to add to the exception event. \item \code{...}: Passed to the \code{span$add_event()} method. } } \subsection{Value}{ The span object itself, invisibly. } } \subsection{\code{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. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$set_attribute(name, value) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: Attribute name. \item \code{value}: Attribute value. See \code{\link[=as_attributes]{as_attributes()}} for supported R types. You may also use \code{\link[=as_attributes]{as_attributes()}} to convert an R object to an OpenTelemetry attribute value. } } \subsection{Value}{ The span object itself, invisibly. } } \subsection{\code{span$set_status()}}{ Set the status of the span. If the span was created with \code{\link[=start_local_active_span]{start_local_active_span()}}, or it was ended automatically with \code{\link[=local_active_span]{local_active_span()}} or \code{\link[=with_active_span]{with_active_span()}}, then otel sets the status of the span automatically to \code{ok} or \code{error}, depending on whether an error happened in the frame the span was activated for. Otherwise the default span status is \code{unset}, and you need to set it manually. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$set_status(status_code, description = NULL) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{status_code}: Possible values: unset, ok, error. \item \code{description}: Optional description, a string. } } \subsection{Value}{ The span itself, invisibly. } } \subsection{\code{span$update_name()}}{ Update the span's name. Overrides the name give in \code{\link[=start_local_active_span]{start_local_active_span()}} or \code{\link[=start_span]{start_span()}}. It is undefined whether a sampler will use the original or the new name. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{span$update_name(name) }\if{html}{\out{
}} } \subsection{Arguments}{ \itemize{ \item \code{name}: String, the new span name. } } \subsection{Value}{ The span object itself, invisibly. } } } \examples{ 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() } \seealso{ Other low level trace API: \code{\link{get_default_tracer_provider}()}, \code{\link{get_tracer}()}, \code{\link{otel_span_context}}, \code{\link{otel_tracer}}, \code{\link{otel_tracer_provider}}, \code{\link{tracer_provider_noop}} } \concept{low level trace API} otel/man/start_local_active_span.Rd0000644000176200001440000000541715046400601017145 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{start_local_active_span} \alias{start_local_active_span} \title{Start and activate a span} \usage{ start_local_active_span( name = NULL, attributes = NULL, links = NULL, options = NULL, ..., tracer = NULL, activation_scope = parent.frame(), end_on_exit = TRUE ) } \arguments{ \item{name}{Name of the span. If not specified it will be \code{""}.} \item{attributes}{Span attributes. OpenTelemetry supports the following R types as attributes: `character, logical, double, integer. You may use \code{\link[=as_attributes]{as_attributes()}} to convert other R types to OpenTelemetry attributes.} \item{links}{A named list of links to other spans. Every link must be an OpenTelemetry span (\link{otel_span}) object, or a list with a span object as the first element and named span attributes as the rest.} \item{options}{A named list of span options. May include: \itemize{ \item \code{start_system_time}: Start time in system time. \item \code{start_steady_time}: Start time using a steady clock. \item \code{parent}: A parent span or span context. If it is \code{NA}, then the span has no parent and it will be a root span. If it is \code{NULL}, then the current context is used, i.e. the active span, if any. \item \code{kind}: Span kind, one of \link{span_kinds}: "internal", "server", "client", "producer", "consumer".}} \item{...}{Additional arguments are passed to the \code{start_span()} method of the tracer.} \item{tracer}{A tracer object or the name of the tracer to use, see \code{\link[=get_tracer]{get_tracer()}}. If \code{NULL} then \code{\link[=default_tracer_name]{default_tracer_name()}} is used.} \item{activation_scope}{The R scope to activate the span for. Defaults to the caller frame.} \item{end_on_exit}{Whether to also end the span when the activation scope exits.} } \value{ The new OpenTelemetry span object (of class \link{otel_span}), invisibly. See \link{otel_span} for information about the returned object. } \description{ Creates, starts and activates an OpenTelemetry span. Usually you want this functions instead of \code{\link[=start_span]{start_span()}}, which does not activate the new span. } \details{ If \code{end_on_exit} is \code{TRUE} (the default), then it also ends the span when the activation scope finishes. } \examples{ fn1 <- function() { otel::start_local_active_span("fn1") fn2() } fn2 <- function() { otel::start_local_active_span("fn2") } fn1() } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{is_tracing_enabled}()}, \code{\link{local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} otel/man/is_measuring_enabled.Rd0000644000176200001440000000215115046400601016411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{is_measuring_enabled} \alias{is_measuring_enabled} \title{Check whether OpenTelemetry metrics collection is active} \usage{ is_measuring_enabled(meter = NULL) } \arguments{ \item{meter}{Meter object (\link{otel_meter}), or a meter name, the instrumentation scope, to pass to \code{\link[=get_meter]{get_meter()}}.} } \value{ \code{TRUE} is OpenTelemetry metrics collection is active, \code{FALSE} otherwise. } \description{ This is useful for avoiding computation when metrics collection is inactive. } \details{ It calls \code{\link[=get_meter]{get_meter()}} with \code{name} and then it calls the meter's \verb{$is_enabled()} method. } \examples{ fun <- function() { if (otel::is_measuring_enabled()) { xattr <- calculate_some_extra_attributes() otel::counter_add("sessions", 1, attributes = xattr) } # ... } } \seealso{ Other OpenTelemetry metrics API: \code{\link{counter_add}()}, \code{\link{gauge_record}()}, \code{\link{histogram_record}()}, \code{\link{up_down_counter_add}()} } \concept{OpenTelemetry metrics API} otel/man/is_tracing_enabled.Rd0000644000176200001440000000247615046400601016060 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{is_tracing_enabled} \alias{is_tracing_enabled} \title{Check if tracing is active} \usage{ is_tracing_enabled(tracer = NULL) } \arguments{ \item{tracer}{Tracer object (\link{otel_tracer}). It can also be a tracer name, the instrumentation scope, or \code{NULL} for determining the tracer name automatically. Passed to \code{\link[=get_tracer]{get_tracer()}} if not a tracer object.} } \value{ \code{TRUE} is OpenTelemetry tracing is active, \code{FALSE} otherwise. } \description{ Checks whether OpenTelemetry tracing is active. This can be useful to avoid unnecessary computation when tracing is inactive. } \details{ It calls \code{\link[=get_tracer]{get_tracer()}} with \code{name} and then it calls the tracer's \verb{$is_enabled()} method. } \examples{ fun <- function() { if (otel::is_tracing_enabled()) { xattr <- calculate_some_extra_attributes() otel::start_local_active_span("fun", attributes = xattr) } # ... } } \seealso{ Other OpenTelemetry trace API: \code{\link{Zero Code Instrumentation}}, \code{\link{end_span}()}, \code{\link{local_active_span}()}, \code{\link{start_local_active_span}()}, \code{\link{start_span}()}, \code{\link{tracing-constants}}, \code{\link{with_active_span}()} } \concept{OpenTelemetry trace API} otel/man/histogram_record.Rd0000644000176200001440000000225515046400601015612 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/api.R \name{histogram_record} \alias{histogram_record} \title{Record a value of an OpenTelemetry histogram} \usage{ histogram_record(name, value, attributes = NULL, context = NULL, meter = NULL) } \arguments{ \item{name}{Name of the histogram.} \item{value}{Value to record.} \item{attributes}{Additional attributes to add.} \item{context}{Span context. If missing the active context is used, if any.} \item{meter}{Meter object (\link{otel_meter}). Otherwise it is passed to \code{\link[=get_meter]{get_meter()}} to get a meter.} } \value{ The histogram object (\link{otel_histogram}), invisibly. } \description{ Record a value of an OpenTelemetry histogram } \examples{ otel::histogram_record("response-time", 0.2) } \seealso{ Other OpenTelemetry metrics instruments: \code{\link{counter_add}()}, \code{\link{gauge_record}()}, \code{\link{up_down_counter_add}()} Other OpenTelemetry metrics API: \code{\link{counter_add}()}, \code{\link{gauge_record}()}, \code{\link{is_measuring_enabled}()}, \code{\link{up_down_counter_add}()} } \concept{OpenTelemetry metrics API} \concept{OpenTelemetry metrics instruments} otel/DESCRIPTION0000644000176200001440000000254515054325537012742 0ustar liggesusersPackage: otel Title: OpenTelemetry R API Version: 0.2.0 Authors@R: person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")) 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: . Use this package as a dependency if you want to instrument your R package for OpenTelemetry. License: MIT + file LICENSE Encoding: UTF-8 RoxygenNote: 7.3.2.9000 Depends: R (>= 3.6.0) Suggests: callr, cli, glue, jsonlite, otelsdk, processx, shiny, spelling, testthat (>= 3.0.0), utils, withr Config/Needs/website: tidyverse/tidytemplate Config/testthat/edition: 3 URL: https://otel.r-lib.org, https://github.com/r-lib/otel Additional_repositories: https://github.com/r-lib/otelsdk/releases/download/devel BugReports: https://github.com/r-lib/otel/issues NeedsCompilation: no Packaged: 2025-08-29 12:46:28 UTC; gaborcsardi Author: Gábor Csárdi [aut, cre] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2025-08-29 13:30:07 UTC