diff --git a/content/en/docs/instrumentation/erlang/_index.md b/content/en/docs/instrumentation/erlang/_index.md index 2a216a82d8b6..3cf9be490608 100644 --- a/content/en/docs/instrumentation/erlang/_index.md +++ b/content/en/docs/instrumentation/erlang/_index.md @@ -15,4 +15,17 @@ Packages of the API, SDK and OTLP exporter are published to [opentelemetry](https://hex.pm/packages/opentelemetry) and [opentelemetry_exporter](https://hex.pm/packages/opentelemetry_exporter). +## Version support + +OpenTelemetry Erlang supports Erlang 23+ and Elixir 1.13+. + +## Repositories + +- [opentelemetry-erlang](https://github.com/open-telemetry/opentelemetry-erlang): + Main repo containing the API, SDK and OTLP Exporter. +- [opentelemetry-erlang-contrib](https://github.com/open-telemetry/opentelemetry-erlang-contrib): + Helpful libraries and instrumentation libraries for Erlang/Elixir projects + like [Phoenix](https://www.phoenixframework.org/) and + [Ecto](https://hexdocs.pm/ecto/Ecto.html) + {{% /lang_instrumentation_index_head %}} diff --git a/content/en/docs/instrumentation/erlang/getting-started.md b/content/en/docs/instrumentation/erlang/getting-started.md index 5f7881afdafb..17e80a2313ac 100644 --- a/content/en/docs/instrumentation/erlang/getting-started.md +++ b/content/en/docs/instrumentation/erlang/getting-started.md @@ -7,31 +7,7 @@ Welcome to the OpenTelemetry for Erlang/Elixir getting started guide! This guide will walk you through the basic steps in installing, configuring, and exporting data from OpenTelemetry. -## Installation - -OpenTelemetry packages for Erlang/Elixir are available on -[hex.pm](https://hex.pm). There are two packages you might want to install, -depending on what you are trying to accomplish. - -### `opentelemetry_api` - -If you are developing a library or OTP Application that someone else would -include into their deployed code and you want to provide OpenTelemetry -instrumentation for them, you'll want to add the dependency `opentelemetry_api`. -This package contains only the API of OpenTelemetry. It will not start any -processes and all API calls (such as starting a span) will be a no-op that -creates no data, unless the `opentelemetry` SDK package is also installed. - -### `opentelemetry` - -If you are developing an Application that will actually be deployed and export -OpenTelemetry data, whether from instrumented dependencies or your code itself, -you'll want to add the `opentelemetry` package. This is the implementation of -the API and will start a Supervision tree, handling the necessary components for -recording and exporting OpenTelemetry signals. This is the package where you -would configure the destination(s) for your OpenTelemetry data, whether it be to -an OpenTelemetry Collector instance, or directly to a vendor's data ingestion -API. +## Creating a New Project To get started with this guide, create a new project with `rebar3` or `mix`: @@ -57,15 +33,15 @@ run as a Release and export spans from. {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -{deps, [{opentelemetry_api, "~> 1.0"}, - {opentelemetry, "~> 1.0"}]}. +{deps, [{opentelemetry_api, "~> 1.2"}, + {opentelemetry, "~> 1.3"}]}. {{< /tab >}} {{< tab Elixir >}} def deps do [ - {:opentelemetry_api, "~> 1.0"}, - {:opentelemetry, "~> 1.0"} + {:opentelemetry_api, "~> 1.2"}, + {:opentelemetry, "~> 1.3"} ] end {{< /tab >}} @@ -73,27 +49,35 @@ end {{< /tabpane >}} -In the case of Erlang, the Applications will also need to be added to -`src/otel_getting_started.app.src`. In an Elixir project, a `releases` section -needs to be added to `mix.exs`: +In the case of Erlang, the API Application will also need to be added to +`src/otel_getting_started.app.src` and a `relx` section to `rebar.config`. In an +Elixir project, a `releases` section needs to be added to `mix.exs`: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} +%% src/otel_getting_started.app.src ... {applications, [kernel, stdlib, - opentelemetry_api, - opentelemetry]}, + opentelemetry_api]}, ... + +%% rebar.config +{relx, [{release, {otel_getting_started, "0.1.0"}, + [{opentelemetry, temporary}, + otel_getting_started]}, + + ...]}. {{< /tab >}} {{< tab Elixir >}} +# mix.exs releases: [ otel_getting_started: [ version: "0.0.1", - applications: [otel_getting_started: :permanent] + applications: [opentelemetry: :temporary, otel_getting_started: :permanent] ] ] {{< /tab >}} @@ -101,14 +85,24 @@ releases: [ {{< /tabpane >}} +The SDK `opentelemetry` should be added as early as possible in the Release boot +process to ensure it is available before any telemetry is produced. Here it is +also set to `temporary` under the assumption that we prefer to have a running +Release not producing telemetry over crashing the entire Release. + +In addition to the API and SDK, an exporter for getting data out is needed. The +SDK comes with an exporter for debugging purposes that prints to stdout and +there are separate packages for exporting over the +[OpenTelemetry Protocol (OTLP)](https://hex.pm/packages/opentelemetry_exporter) +and the [Zipkin protocol](https://hex.pm/packages/opentelemetry_zipkin). + ## Initialization and Configuration Configuration is done through the [Application environment](https://erlang.org/doc/design_principles/applications.html#configuring-an-application) -or -[OS Environment Variables](/docs/reference/specification/sdk-environment-variables/). -The `opentelemetry` Application uses the configuration to initialize a -[Tracer Provider](https://hexdocs.pm/opentelemetry_api/otel_tracer_provider.html), +or [OS Environment Variables]({{< relref +"/docs/reference/specification/sdk-environment-variables" >}}). The SDK (`opentelemetry` +Application) uses the configuration to initialize a [Tracer Provider](https://hexdocs.pm/opentelemetry_api/otel_tracer_provider.html), its [Span Processors](https://hexdocs.pm/opentelemetry/otel_span_processor.html) and the [Exporter](https://hexdocs.pm/opentelemetry/otel_exporter.html). @@ -165,7 +159,7 @@ with a function `hello/0` that starts some spans: hello() -> %% start an active span and run a local function - ?with_span(<<"operation">>, #{}, fun nice_operation/1). + ?with_span(operation, #{}, fun nice_operation/1). nice_operation(_SpanCtx) -> ?add_event(<<"Nice operation!">>, [{<<"bogons">>, 100}]), @@ -185,7 +179,7 @@ defmodule OtelGettingStarted do require OpenTelemetry.Tracer, as: Tracer def hello do - Tracer.with_span "operation" do + Tracer.with_span :operation do Tracer.add_event("Nice operation!", [{"bogons", 100}]) Tracer.set_attributes([{:another_key, "yes"}]) @@ -244,7 +238,7 @@ true [{event,-576460750077786044,<<"Sub span event!">>,[]}], [],undefined,1,false,undefined} {span,177312096541376795265675405126880478701,13736713257910636645,undefined, - undefined,<<"operation">>,internal,-576460750086570890, + undefined,operation,internal,-576460750086570890, -576460750077752627, [{another_key,<<"yes">>}], [{event,-576460750077877345,<<"Nice operation!">>,[{<<"bogons">>,100}]}], @@ -268,7 +262,7 @@ iex(2)> [{event,-576460741349414157,<<"Sub span event!">>,[]}], [],undefined,1,false,undefined} {span,180094370450826032544967824850795294459,14276444653144535440,undefined, - undefined,<<"operation">>,'INTERNAL',-576460741353342627, + undefined,:operation,'INTERNAL',-576460741353342627, -576460741349400034, [{another_key,<<"yes">>}], [{event,-576460741349446725,<<"Nice operation!">>,[{<<"bogons">>,100}]}], @@ -303,17 +297,17 @@ added to the project's dependencies: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -{deps, [{opentelemetry_api, "~> 1.0"}, - {opentelemetry, "~> 1.0"}, - {opentelemetry_exporter, "~> 1.0"}]}. +{deps, [{opentelemetry_api, "~> 1.3"}, + {opentelemetry, "~> 1.3"}, + {opentelemetry_exporter, "~> 1.4"}]}. {{< /tab >}} {{< tab Elixir >}} def deps do [ - {:opentelemetry_api, "~> 1.0"}, - {:opentelemetry, "~> 1.0"}, - {:opentelemetry_exporter, "~> 1.0"} + {:opentelemetry_api, "~> 1.3"}, + {:opentelemetry, "~> 1.3"}, + {:opentelemetry_exporter, "~> 1.4"} ] end {{< /tab >}} @@ -321,9 +315,9 @@ end {{< /tabpane >}} -It should then be added to the configuration of the Release, it should be before -the SDK Application to ensure the exporter's dependencies are started before the -SDK attempts to initialize and use the exporter. +It should then be added to the configuration of the Release before the SDK +Application to ensure the exporter's dependencies are started before the SDK +attempts to initialize and use the exporter. Example of Release configuration in `rebar.config` and for [mix's Release task](https://hexdocs.pm/mix/Mix.Tasks.Release.html): diff --git a/content/en/docs/instrumentation/erlang/instrumentation.md b/content/en/docs/instrumentation/erlang/instrumentation.md index 294c358637dc..65d5342c5fae 100644 --- a/content/en/docs/instrumentation/erlang/instrumentation.md +++ b/content/en/docs/instrumentation/erlang/instrumentation.md @@ -8,92 +8,97 @@ This can be done with direct calls to the OpenTelemetry API within your code or including a dependency which calls the API and hooks into your project, like a middleware for an HTTP server. -## TracerProvider and Tracers +## Tracing -In OpenTelemetry each service being traced has at least one `TracerProvider` -that is used to hold configuration about the name/version of the service, what -sampler to use and how to process/export the spans. A `Tracer` is created by a -`TracerProvider` and has a name and version. In the Erlang/Elixir OpenTelemetry -the name and version of each `Tracer` is the same as the name and version of the -OTP Application the module using the `Tracer` is in. If the call to use a -`Tracer` is not in a module, for example when using the interactive shell, the -default `Tracer` is used. +### Initialize Tracing + +To start [tracing](/docs/concepts/signals/traces/) a +[`TracerProvider`](/docs/concepts/signals/traces/#tracer-provider) is required +for creating a [`Tracer`](/docs/concepts/signals/traces/#tracer). When the +OpenTelemetry SDK Application (`opentelemetry`) boots, it starts and configures +a global `TracerProvider`. A `Tracer` for each loaded OTP Application is created +once the `TracerProvider` has started. + +If a TracerProvider is not successfully created (for example, the +`opentelemetry` application is not booted or fails to boot), the OpenTelemetry +APIs for tracing will use a no-op implementation and will not generate data. + +### Acquiring a Tracer Each OTP Application has a `Tracer` created for it when the `opentelemetry` -Application boots. This can be disabled by setting the Application environment -variable `create_application_tracers` to `false`. If you want a more specific -name for a `Tracer` you can create a `Tracer` with a name and version and pass -it manually to `otel_tracer` or `OpenTelemetry.Tracer`. Examples: +Application boots. The name and version of each `Tracer` is the same as the name +and version of the OTP Application the module using the `Tracer` is in. If the +call to use a `Tracer` is not in a module, for example when using the +interactive shell, a `Tracer` with a blank name and version is used. + +The created `Tracer`'s record can be looked up by the name of a module in the +OTP Application: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -Tracer = opentelemetry:get_tracer(test_tracer), -SpanCtx = otel_tracer:start_span(Tracer, <<"hello-world">>, #{}), -... -otel_tracer:end_span(SpanCtx). +opentelemetry:get_application_tracer(?MODULE) {{< /tab >}} {{< tab Elixir >}} -tracer = OpenTelemetry.get_tracer(:test_tracer) -span_ctx = OpenTelemetry.Tracer.start_span(tracer, "hello-world", %{}) +:opentelemetry.get_application_tracer(__MODULE__) +{{< /tab >}} + +{{< /tabpane >}} + + +This is how the Erlang and Elixir macros for starting and updating `Spans` get a +`Tracer` automatically without need for you to pass the variable in each call. + +### Create Spans + +Now that you have [Tracer](/docs/concepts/signals/traces/#tracer)s initialized, +you can create [Spans](/docs/concepts/signals/traces/#spans-in-opentelemetry). + + +{{< tabpane langEqualsHeader=true >}} + +{{< tab Erlang >}} +?with_span(main, #{}, fun() -> + %% do work here. + %% when this function returns the Span ends + end). + +{{< /tab >}} + +{{< tab Elixir >}} +require OpenTelemetry.Tracer + ... -OpenTelemetry.Tracer.end_span(span_ctx) + +OpenTelemetry.Tracer.with_span :main do + # do work here + # when the block ends the Span ends +end {{< /tab >}} {{< /tabpane >}} -In most cases you will not need to manually create a `Tracer`. Simply use the -macros provided, which are covered in the following section, and the `Tracer` -for the Application the macro is used in will be used automatically. - -Giving names to each `Tracer`, and in the case of Erlang/Elixir having that name -be the name of the Application, allows for the ability to blacklist traces from -a particular Application. This can be useful if, for example, a dependency turns -out to be generating too many or in some way problematic spans and it is desired -to disable their generation. - -Additionally, the name and version of the `Tracer` are exported as the -[`InstrumentationLibrary`](/docs/reference/specification/glossary/#instrumentation-library) -component of spans. This allows users to group and search spans by the -Application they came from. - -## Starting Spans - -A trace is a tree of spans, starting with a root span that has no parent. To -represent this tree, each span after the root has a parent span associated with -it. When a span is started the parent is set based on the `context`. A `context` -can either be implicit, meaning your code does not have to pass a `Context` -variable to track the active `context`, or explicit where your code must pass -the `Context` as an argument not only to the OpenTelemetry functions but to any -function you need to propagate the `context` so that spans started in those -functions have the proper parent. - -For implicit context propagation across functions within a process the -[process dictionary](https://erlang.org/doc/reference_manual/processes.html#process-dictionary) -is used to store the context. When you start a span with the macro `with_span` -the context in the process dictionary is updated to make the newly started span -the currently active span and this span will be end'ed when the block or -function completes. Additionally, starting a new span within the body of -`with_span` will use the active span as the parent of the new span and the -parent is again the active span when the child's block or function body -completes: +The above code sample shows how to create an active Span, which is the most +common kind of Span to create. + +### Create Nested Spans {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} parent_function() -> - ?with_span(<<"parent">>, #{}, fun child_function/0). + ?with_span(parent, #{}, fun child_function/0). child_function() -> - %% this is the same process, so the span <<"parent">> set as the active + %% this is the same process, so the span parent set as the active %% span in the with_span call above will be the active span in this function - ?with_span(<<"child">>, #{}, + ?with_span(child, #{}, fun() -> - %% do work here. when this function returns, <<"child">> will complete. + %% do work here. when this function returns, child will complete. end). {{< /tab >}} @@ -102,16 +107,16 @@ child_function() -> require OpenTelemetry.Tracer def parent_function() do - OpenTelemetry.Tracer.with_span "parent" do + OpenTelemetry.Tracer.with_span :parent do child_function() end end def child_function() do - # this is the same process, so the span <<"parent">> set as the active + # this is the same process, so the span :parent set as the active # span in the with_span call above will be the active span in this function - OpenTelemetry.Tracer.with_span "child" do - ## do work here. when this function returns, <<"child">> will complete. + OpenTelemetry.Tracer.with_span :child do + ## do work here. when this function returns, :child will complete. end end {{< /tab >}} @@ -119,18 +124,16 @@ end {{< /tabpane >}} -### Cross Process Propagation +### Spans in Separate Processes -The examples in the previous section were spans with a child-parent relationship +The examples in the previous section were Spans with a child-parent relationship within the same process where the parent is available in the process dictionary -when creating a child span. Using the process dictionary this way isn't possible +when creating a child Span. Using the process dictionary this way isn't possible when crossing processes, either by spawning a new process or sending a message to an existing process. Instead, the context must be manually passed as a variable. -#### Creating Spans for New Processes - -To pass spans across processes we need to start a span that isn't connected to +To pass Spans across processes we need to start a Span that isn't connected to particular process. This can be done with the macro `start_span`. Unlike `with_span`, the `start_span` macro does not set the new span as the currently active span in the context of the process dictionary. @@ -144,7 +147,8 @@ telemetry data like [baggage](/docs/reference/specification/baggage/api/). {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -SpanCtx = ?start_span(<<"child">>), +SpanCtx = ?start_span(child), + Ctx = otel_ctx:get_current(), proc_lib:spawn_link(fun() -> @@ -158,7 +162,7 @@ proc_lib:spawn_link(fun() -> {{< /tab >}} {{< tab Elixir >}} -span_ctx = OpenTelemetry.Tracer.start_span(<<"child">>) +span_ctx = OpenTelemetry.Tracer.start_span(:child) ctx = OpenTelemetry.Ctx.get_current() task = Task.async(fn -> @@ -176,14 +180,12 @@ _ = Task.await(task) {{< /tabpane >}} -#### Linking the New Span +### Linking the New Span -If the work being done by the other process is better represented as a `link` -- -see -[the `link` definition in the specification](/docs/reference/specification/overview/#links-between-spans) -for more on when that is appropriate -- then the `SpanCtx` returned by -`start_span` is passed to `link/1` to create a `link` that can be passed to -`with_span` or `start_span`: +A [Span](/docs/concepts/signals/traces/#spans-in-opentelemetry) can be created +with zero or more Span Links that causally link it to another Span. A +[Link](/docs/concepts/signals/traces/#span-links) needs a Span context to be +created. {{< tabpane langEqualsHeader=true >}} @@ -194,7 +196,7 @@ proc_lib:spawn_link(fun() -> %% a new process has a new context so the span created %% by the following `with_span` will have no parent Link = opentelemetry:link(Parent), - ?with_span(<<"other-process">>, #{links => [Link]}, + ?with_span('other-process', #{links => [Link]}, fun() -> ok end) end), {{< /tab >}} @@ -205,7 +207,7 @@ task = Task.async(fn -> # a new process has a new context so the span created # by the following `with_span` will have no parent link = OpenTelemetry.link(parent) - Tracer.with_span "my-task", %{links: [link]} do + Tracer.with_span :"my-task", %{links: [link]} do :hello end end) @@ -214,17 +216,11 @@ task = Task.async(fn -> {{< /tabpane >}} -### Attributes - -Attributes are key-value pairs that are applied as metadata to your spans and -are useful for aggregating, filtering, and grouping traces. Attributes can be -added at span creation, or at any other time during the life cycle of a span -before it has completed. +### Adding Attributes to a Span -The key can be an atom or a utf8 string (a regular string in Elixir and a -binary, `<<"..."/utf8>>`, in Erlang). The value can be of any type. If necessary -the key and value are converted to strings when the attribute is exported in a -span. +[Attributes](/docs/concepts/signals/traces/#attributes) let you attach key/value +pairs to a Span so it carries more information about the current operation that +it’s tracking. The following example shows the two ways of setting attributes on a span by both setting an attribute in the start options and then again with `set_attributes` @@ -234,16 +230,16 @@ in the body of the span operation: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -?with_span(<<"my-span">>, #{attributes => [{<<"start-opts-attr">>, <<"start-opts-value">>}]}, +?with_span(my_span, #{attributes => [{'start-opts-attr', <<"start-opts-value">>}]}, fun() -> - ?set_attributes([{<<"my-attribute">>, <<"my-value">>}, + ?set_attributes([{'my-attribute', <<"my-value">>}, {another_attribute, <<"value-of-attribute">>}]) end) {{< /tab >}} {{< tab Elixir >}} -Tracer.with_span "span-1", %{attributes: [{<<"start-opts-attr">>, <<"start-opts-value">>}]} do - Tracer.set_attributes([{"my-attributes", "my-value"}, +Tracer.with_span :span_1, %{attributes: [{:"start-opts-attr", <<"start-opts-value">>}]} do + Tracer.set_attributes([{:"my-attributes", "my-value"}, {:another_attribute, "value-of-attributes"}]) end {{< /tab >}} @@ -251,124 +247,118 @@ end {{< /tabpane >}} -#### Semantic Attributes +### Semantic Attributes Semantic Attributes are attributes that are defined by the [OpenTelemetry Specification][] in order to provide a shared set of attribute keys across multiple languages, frameworks, and runtimes for common concepts like HTTP -methods, status codes, user agents, and more. These attribute keys and values -are available in the header `opentelemetry_api/include/otel_resource.hrl`. +methods, status codes, user agents, and more. These attribute keys are generated +from the specification and provided in +[opentelemetry_semantic_conventions](https://hex.pm/packages/opentelemetry_semantic_conventions). -For details, see [Trace semantic conventions][]. - -### Events - -An event is a human-readable message on a span that represents "something -happening" during it's lifetime. For example, imagine a function that requires -exclusive access to a resource like a database connection from a pool. An event -could be created at two points - once, when the connection is checked out from -the pool, and another when it is checked in. +For example, an instrumentation for an HTTP client or server would need to +include semantic attributes like the scheme of the URL: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -?with_span(<<"my-span">>, #{}, +-include_lib("opentelemetry_semantic_conventions/include/trace.hrl"). + +?with_span(my_span, #{attributes => [{?HTTP_SCHEME, <<"https">>}]}, fun() -> - ?add_event(<<"checking out connection">>), - %% acquire connection from connection pool - ?add_event(<<"got connection, doing work">>), - %% do some work with the connection and then return it to the pool - ?add_event(<<"checking in connection">>) + ... end) {{< /tab >}} {{< tab Elixir >}} -Tracer.with_span "my-span" do - Span.add_event("checking out connection") - # acquire connection from connection pool - Span.add_event("got connection, doing work") - # do some work with the connection and then return it to the pool - Span.add_event("checking in connection") +alias OpenTelemetry.SemanticConventions.Trace, as: Trace + +Tracer.with_span :span_1, %{attributes: [{Trace.http_scheme(), <<"https">>}]} do + end {{< /tab >}} {{< /tabpane >}} - -A useful characteristic of events is that their timestamps are displayed as -offsets from the beginning of the span, allowing you to easily see how much time -elapsed between them. +### Adding Events -Additionally, events can also have attributes of their own: +A [Span +Event](/docs/concepts/signals/traces/#span-events) is a +human-readable message on an +[Span](/docs/concepts/signals/traces/#spans-in-opentelemetry) +that represents a discrete event with no duration that can be tracked by a +single time stamp. You can think of it like a primitive log. {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -?add_event("Process exited with reason", [{pid, Pid)}, {reason, Reason}])) +?add_event(<<"Gonna try it">>), + +%% Do the thing + +?add_event(<<"Did it!">>), {{< /tab >}} {{< tab Elixir >}} -Span.add_event("Process exited with reason", pid: pid, reason: Reason) +Tracer.add_event("Gonna try it") + +%% Do the thing + +Tracer.add_event("Did it!") {{< /tab >}} {{< /tabpane >}} -## Cross Service Propagators - -Distributed traces extend beyond a single service, meaning some context must be -propagated across services to create the parent-child relationship between -spans. This requires cross service -[_context propagation_](/docs/reference/specification/overview/#context-propagation), -a mechanism where identifiers for a trace are sent to remote processes. - -In order to propagate trace context over the wire, a propagator must be -registered with OpenTelemetry. This can be done through configuration of the -`opentelemetry` application: +Events can also have attributes of their own: {{< tabpane langEqualsHeader=true >}} {{< tab Erlang >}} -%% sys.config -... -{text_map_propagators, [baggage, - trace_context]}, -... +?add_event(<<"Process exited with reason">>, [{pid, Pid)}, {reason, Reason}])) {{< /tab >}} {{< tab Elixir >}} -## runtime.exs -... -text_map_propagators: [:baggage, :trace_context], -... +Tracer.add_event("Process exited with reason", pid: pid, reason: Reason) {{< /tab >}} {{< /tabpane >}} -If you instead need to use the -[B3 specification](https://github.com/openzipkin/b3-propagation), originally -from the [Zipkin project](https://zipkin.io/), then replace `trace_context` and -`:trace_context` with `b3` and `:b3` for Erlang or Elixir respectively. +### Set Span Status + +A [Status](/docs/concepts/signals/traces/#span-status) can be set on a +[Span](/docs/concepts/signals/traces/#spans-in-opentelemetry), typically used to +specify that a Span has not completed successfully - `StatusCode.ERROR`. In rare +scenarios, you could override the Error status with `StatusCode.OK`, but don’t +set `StatusCode.OK` on successfully-completed spans. + +The status can be set at any time before the span is finished: + + +{{< tabpane langEqualsHeader=true >}} + +{{< tab Erlang >}} +-include_lib("opentelemetry_api/include/opentelemetry.hrl"). -## Library Instrumentation +?set_status(?OTEL_STATUS_ERROR, <<"this is not ok">>) +{{< /tab >}} -Library instrumentations, broadly speaking, refers to instrumentation code that -you didn't write but instead include through another library. OpenTelemetry for -Erlang/Elixir supports this process through wrappers and helper functions around -many popular frameworks and libraries. You can find in the -[opentelemetry-erlang-contrib repo](https://github.com/open-telemetry/opentelemetry-erlang-contrib/), -published to [hex.pm](https://hex.pm) under the -[OpenTelemetry Organization](https://hex.pm/orgs/opentelemetry) and the -[registry](/ecosystem/registry/). +{{< tab Elixir >}} +Tracer.set_status(:error, "this is not ok") +{{< /tab >}} + +{{< /tabpane >}} + ## Creating Metrics -The metrics API, found in `apps/opentelemetry-experimental-api` of the -`opentelemetry-erlang` repository, is currently unstable, documentation TBA. +The metrics API, found in `apps/opentelemetry_experimental_api` of the +[opentelemetry-erlang](https://github.com/open-telemetry/opentelemetry-erlang) +repository, is currently unstable, documentation TBA. [opentelemetry specification]: /docs/reference/specification/ [trace semantic conventions]: diff --git a/content/en/docs/instrumentation/erlang/propagation.md b/content/en/docs/instrumentation/erlang/propagation.md new file mode 100644 index 000000000000..3ae7b7c38d22 --- /dev/null +++ b/content/en/docs/instrumentation/erlang/propagation.md @@ -0,0 +1,82 @@ +--- +title: Propagation +weight: 35 +--- + +## Cross Service Propagators + +Distributed traces extend beyond a single service, meaning some context must be +propagated across services to create the parent-child relationship between +Spans. This requires cross service [_context +propagation_]({{< relref "/docs/reference/specification/overview#context-propagation" >}}), +a mechanism where identifiers for a Trace are sent to remote processes. + +Instrumentation Libraries for HTTP frameworks and servers like +[Phoenix](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_phoenix), +[Cowboy](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_cowboy), +[Elli](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_elli) +and clients like +[Tesla](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_tesla) +will automatically inject or extract context using the globally registered +propagators. By default the global propagators used are the W3C +[Trace Context](https://w3c.github.io/trace-context/) and +[Baggage](https://www.w3.org/TR/baggage/) formats. + +These global propagators can be configured by the Application environment +variable `text_map_propagators`: + + +{{< tabpane langEqualsHeader=true >}} + +{{< tab Erlang >}} +%% sys.config +... +{text_map_propagators, [baggage, + trace_context]}, +... +{{< /tab >}} + +{{< tab Elixir >}} +## runtime.exs +... +text_map_propagators: [:baggage, :trace_context], +... +{{< /tab >}} + +{{< /tabpane >}} + + +Or through a comma separated list with the environment variable +`OTEL_PROPAGATORS`. Both forms of configuration accept the values +`trace_context`, `baggage`, [`b3`](https://github.com/openzipkin/b3-propagation) +and `b3multi`. + +To manually inject or extract context the `otel_propagator_text_map` module can +be used: + + +{{< tabpane langEqualsHeader=true >}} + +{{< tab Erlang >}} +%% uses the context from the process dictionary to add to an empty list of headers +Headers = otel_propagator_text_map:inject([]), + +%% creates a context in the process dictionary from Headers +otel_propagator_text_map:extract(Headers), +{{< /tab >}} + +{{< tab Elixir >}} +# uses the context from the process dictionary to add to an empty list of headers +headers = :otel_propagator_text_map.inject([]) + +# creates a context in the process dictionary from headers +:otel_propagator_text_map.extract(headers) +{{< /tab >}} + +{{< /tabpane >}} + + +`otel_propagator_text_map:inject/1` and `otel_propagator_text_map:extract/1` use +globally registered propagators. To use a specific propagator +`otel_propagator_text_map:inject/2` and `otel_propagator_text_map:extract/2` can +be used with the first argument being the name of the propagator module to call. diff --git a/static/refcache.json b/static/refcache.json index 7ab47856a262..0ebc7ade8811 100644 --- a/static/refcache.json +++ b/static/refcache.json @@ -1939,6 +1939,10 @@ "StatusCode": 200, "LastSeen": "2023-02-20T07:45:31.864938-05:00" }, + "https://github.com/open-telemetry/opentelemetry-erlang-contrib": { + "StatusCode": 200, + "LastSeen": "2023-03-29T12:11:58.789694604-06:00" + }, "https://github.com/open-telemetry/opentelemetry-erlang-contrib/": { "StatusCode": 200, "LastSeen": "2023-02-20T07:55:02.471109-05:00" @@ -2611,6 +2615,18 @@ "StatusCode": 200, "LastSeen": "2023-02-15T21:47:24.160442-05:00" }, + "https://hex.pm/packages/opentelemetry_semantic_conventions": { + "StatusCode": 200, + "LastSeen": "2023-03-29T12:11:58.011874587-06:00" + }, + "https://hex.pm/packages/opentelemetry_zipkin": { + "StatusCode": 200, + "LastSeen": "2023-03-29T12:11:58.253221854-06:00" + }, + "https://hexdocs.pm/ecto/Ecto.html": { + "StatusCode": 206, + "LastSeen": "2023-03-29T12:11:59.363133963-06:00" + }, "https://hexdocs.pm/mix/Mix.Tasks.Release.html": { "StatusCode": 206, "LastSeen": "2023-02-15T21:47:40.349021-05:00" @@ -3071,6 +3087,10 @@ "StatusCode": 200, "LastSeen": "2023-02-16T17:43:01.177325-05:00" }, + "https://opentelemetry.io/": { + "StatusCode": 206, + "LastSeen": "2023-03-29T12:11:52.979049301-06:00" + }, "https://opentracing.io": { "StatusCode": 206, "LastSeen": "2023-02-16T17:44:53.820176-05:00" @@ -3931,6 +3951,10 @@ "StatusCode": 200, "LastSeen": "2023-02-18T13:46:19.448057-05:00" }, + "https://www.phoenixframework.org/": { + "StatusCode": 200, + "LastSeen": "2023-03-29T12:11:59.188257421-06:00" + }, "https://www.php-fig.org/psr/psr-15/": { "StatusCode": 206, "LastSeen": "2023-02-28T03:33:34.741771102Z"