Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt

Use this file to discover all available pages before exploring further.

Plugin enhancing observability of Atoti sessions. Projects using Atoti Python SDK will have this kind of architecture: OpenTelemetry distributed tracing allows these different services to contribute their own spans to the same trace. This makes it possible to follow a request across process boundaries, identify bottlenecks, and understand the end-to-end latency of operations. With this plugin enabled, Atoti Server will also expose some metrics through OpenTelemetry. A quick way to get started with observability is to:
  1. Run a Jaeger all-in-one Docker container (or any other OpenTelemetry collector).
  2. Install one of the Python OpenTelemetry exporters.
  3. Install atoti-observability (this plugin).
  4. Call opentelemetry.trace.set_tracer_provider() at the start of the Python application.
  5. Create spans in the application code for each major step.
See the project template for a working example.
When using different ports than the OpenTelemetry’s default ones, do not forget to set os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] before calling atoti.Session.start() so that the Atoti Server launched in a subprocess inherits it and exports its telemetry data to the right place.
This plugin automatically adds the OpenTelemetry Java agent to the server process but this can be changed by passing another -javaagent:* to the java_options.

Example

Here, the OpenTelemetry environment is already configured:
>>> import os
>>> from opentelemetry.sdk.environment_variables import OTEL_EXPORTER_OTLP_ENDPOINT
>>> OTEL_EXPORTER_OTLP_ENDPOINT in os.environ
True
Creating a simple trace with multiple spans:
>>> from opentelemetry.trace import get_tracer
>>> TRACER = get_tracer("example")
>>> with TRACER.start_as_current_span("root") as span:
...     foo = 1
...     with TRACER.start_as_current_span("intermediate"):
...         bar = 2
...         with TRACER.start_as_current_span("leaf"):
...             baz = 3
>>> _print(span)
⏺ root           [atoti.python_sdk]
└── intermediate [atoti.python_sdk]
    └── leaf     [atoti.python_sdk]
Defining a function to avoid duplicating logic below:
>>> def query(session: tt.Session, /):
...     cities_df = pd.DataFrame(
...         columns=["City", "Price"],
...         data=[
...             ("Berlin", 150.0),
...             ("London", 240.0),
...             ("New York", 270.0),
...             ("Paris", 200.0),
...         ],
...     )
...     table = session.read_pandas(cities_df, keys={"City"}, table_name="Example")
...     cube = session.create_cube(table)
...     level = cube.levels["City"]
...     measure = cube.measures["Price.SUM"]
...     with TRACER.start_as_current_span("example query") as span:
...         _ = cube.query(measure, levels=[level])
...     return span
Calling atoti.Cube.query() generates some Python spans:
>>> span = query(session)
>>> _print(span)
⏺ example query                     [atoti.python_sdk]
└── Cube.query                      [atoti.python_sdk]
    ├── generate_mdx                [atoti.python_sdk]
    └── cellset_to_mdx_query_result [atoti.python_sdk]
        ├── Level.data_type         [atoti.python_sdk]
        └── Measure.data_type       [atoti.python_sdk]
Using a session with the observability plugin enabled will also export the server spans:
>>> span = query(session_with_observability_plugin)
>>> _print(span)
⏺ example query                                        [atoti.python_sdk]
└── Cube.query                                         [atoti.python_sdk]
    ├── GET /activeviam/pivot/rest/v10/cube/discovery  [atoti.server]
    │   └── unsecured request                          [atoti.server]
    ├── generate_mdx                                   [atoti.python_sdk]
    ├── POST /activeviam/pivot/rest/v10/cube/query/mdx [atoti.server]
    │   └── unsecured request                          [atoti.server]
    │       └── Json query service                     [atoti.server]
    │           └── select query                       [atoti.server]
    │               └── Async query executor           [atoti.server]
    │                   └── just-in-time query         [atoti.server]
    │                       └── Database query         [atoti.server]
    └── cellset_to_mdx_query_result                    [atoti.python_sdk]
        ├── Level.data_type                            [atoti.python_sdk]
        └── Measure.data_type                          [atoti.python_sdk]