Erlang/Elixir SIG Survey Results #15
Replies: 1 comment
-
While building a sample app for "dogfood" and the OpenTelemetry libraries for .NET, I ran into a scenario similar to the concept of untraced. I wanted a way to decide programmatically (in the instrumentation code) to prevent a current span ( A concrete scenario is writing a handler for a request (in this case, ASP.NET Core middleware) that is expected to be invoked by a third party from a specific set of IPs. The handler may do some relatively expensive IP validation before returning an appropriate response in the case of a request coming from an unexpected IP that might represent a bad actor. In such a case, it is helpful to prevent resource use (storage of logs/spans etc.) for something we decide we don't care about. In that scenario, it is nice to be able to decide that the current span should not be recorded (even if it was marked as sampled) nor enriched by subsequent code. In .NET this is possible with code such as:
A processor was a potential solution, but it doesn't avoid the enriching and child span ( |
Beta Was this translation helpful? Give feedback.
-
As we discussed I'm opening a discussion for the results of the Erlang/Elixir language survey so we can thread any discussion we want to have before I open a PR to add this to the repo.
I'm putting most requested first because it is shorter.
most requested:
An
untraced
functionality is the most requested feature that is not part of the spec. One place this has come up is the instrumentation of the database library Ecto. There are calls to the database that the user does not want a span created for but has no way to disable when using the semi-automated instrumentation library.untraced
would give them a way to disable telemetry within a block and not have spans started where they do not want them and be able to continue using the instrumentation library.Another way to look at this is as wanting more control over the created telemetry, especially when using instrumentation libraries, without relying on a custom sampler or the collector to do filtering.
Access to the "root span" (quoted because it would have to mean the root within the running node and not the actual root which could be remote). I think this comes up because of patterns from some vendors who's libraries rely on either this or having a root "transaction" span. I don't know that it is something to consider adding, especially since
extra convenience:
Tracer/Meter Providers and Metric Readers started on boot:
Providers and readers are created on boot based on the Erlang configuration file
sys.config
– to be replaced with the standard Otel configuration file.Each provider is a process so
?GLOBAL_TRACER_PROVIDER_NAME
is used as the registered name of the process to allow referencing from anywhere in your code. A user can start their own provider withstart_tracer_provider(Name, Config)
and reference it with either the returned Erlang process id (PID) or theName
.Doing this on boot and documenting for the user how to ensure the SDK is the first thing booted after the Erlang kernel/stdlib instead of having the user have to start a provider in their code means there is never a time that user code or dependency code is running without the SDK available, so no spans are sent to the no-op tracer during boot because of no SDK being available.
Tracers/Meters are created on boot:
For each OTP Application (analogous to a library in other languages) in an OTP Release (analogous to a program/application in other languages) a tracer (named and version from the Application name and version) is created with the default global tracer provider and stored in shared state. When a span is started using the macros (provided for both Erlang and Elixir) the tracer for the Application of the current module (found at compile time) is used. The user has the option to use functions instead of macros and to pass a tracer explicitly if they want a different name other than the Application.
This makes starting spans look like:
Rather than:
API macro/function
with_span
:I'm not sure if this needs to be called out. I think every language has one of these in their API but it isn't explicitly in the API. These functions offer a way to pass a code block or function to run with the newly created span as the active span in the context and to then end the span and return to the previous context when it completes:
This means while the
fun
runs it'll start a span namedspanname
, set it as the current active span in the context (context is stored in Erlang's process dictionary) and when thefun
ends the span is ended and any previous context is returned to the active state.Instruments have global atom name:
The same as starting a tracer the creation of instruments is done through a shared process (the provider). This would create a bottleneck if every usage of an instrument involved getting it through the provider. To get around this bottleneck instruments are stored in a shared table (unique per-meter provider) allowing for a user to make a recording using the name rather than the instrument variable:
Beta Was this translation helpful? Give feedback.
All reactions