Tempo Coordinator K8S

  • Canonical Observability
Channel Revision Published Runs on
latest/edge 37 20 Nov 2024
Ubuntu 22.04
juju deploy tempo-coordinator-k8s --channel edge
Show information

Platform:

charms.tempo_coordinator_k8s.v0.tracing

Overview.

This document explains how to integrate with the Tempo charm for the purpose of pushing traces to a tracing endpoint provided by Tempo. It also explains how alternative implementations of the Tempo charm may maintain the same interface and be backward compatible with all currently integrated charms.

Requirer Library Usage

Charms seeking to push traces to Tempo, must do so using the TracingEndpointRequirer object from this charm library. For the simplest use cases, using the TracingEndpointRequirer object only requires instantiating it, typically in the constructor of your charm. The TracingEndpointRequirer constructor requires the name of the relation over which a tracing endpoint is exposed by the Tempo charm, and a list of protocols it intends to send traces with. This relation must use the tracing interface. The TracingEndpointRequirer object may be instantiated as follows

from charms.tempo_coordinator_k8s.v0.tracing import TracingEndpointRequirer

def __init__(self, *args):
    super().__init__(*args)
    # ...
    self.tracing = TracingEndpointRequirer(self,
        protocols=['otlp_grpc', 'otlp_http', 'jaeger_http_thrift']
    )
    # ...

Note that the first argument (self) to TracingEndpointRequirer is always a reference to the parent charm.

Alternatively to providing the list of requested protocols at init time, the charm can do it at any point in time by calling the TracingEndpointRequirer.request_protocols(*protocol:str, relation:Optional[Relation]) method. Using this method also allows you to use per-relation protocols.

Units of requirer charms obtain the tempo endpoint to which they will push their traces by calling TracingEndpointRequirer.get_endpoint(protocol: str), where protocol is, for example:

  • otlp_grpc
  • otlp_http
  • zipkin
  • tempo

If the protocol is not in the list of protocols that the charm requested at endpoint set-up time, the library will raise an error.

We recommend that you scale up your tracing provider and relate it to an ingress so that your tracing requests go through the ingress and get load balanced across all units. Otherwise, if the provider's leader goes down, your tracing goes down.

Provider Library Usage

The TracingEndpointProvider object may be used by charms to manage relations with their trace sources. For this purposes a Tempo-like charm needs to do two things

  1. Instantiate the TracingEndpointProvider object by providing it a reference to the parent (Tempo) charm and optionally the name of the relation that the Tempo charm uses to interact with its trace sources. This relation must conform to the tracing interface and it is strongly recommended that this relation be named tracing which is its default value.

For example a Tempo charm may instantiate the TracingEndpointProvider in its constructor as follows

from charms.tempo_coordinator_k8s.v0.tracing import TracingEndpointProvider

def __init__(self, *args):
    super().__init__(*args)
    # ...
    self.tracing = TracingEndpointProvider(self)
    # ...

class TransportProtocolType

Description

Receiver Type. None

class TracingError

Description

Base class for custom errors raised by this library. None

class NotReadyError

Description

Raised by the provider wrapper if a requirer hasn't published the required data (yet). None

class ProtocolNotRequestedError

Description

Raised if the user attempts to obtain an endpoint for a protocol it did not request. None

class DataValidationError

Description

Raised when data validation fails on IPU relation data. None

class AmbiguousRelationUsageError

Description

Raised when one wrongly assumes that there can only be one relation on an endpoint. None

class Receiver

Description

Specification of an active receiver. None

class TracingProviderAppData

Description

Application databag model for the tracing provider. None

class TracingRequirerAppData

Description

Application databag model for the tracing requirer. None

class RelationNotFoundError

Description

Raised if no relation with the given name is found. None

Methods

RelationNotFoundError. __init__( self , relation_name: str )

class RelationInterfaceMismatchError

Description

Raised if the relation with the given name has an unexpected interface. None

Methods

RelationInterfaceMismatchError. __init__( self , relation_name: str , expected_relation_interface: str , actual_relation_interface: str )

class RelationRoleMismatchError

Description

Raised if the relation with the given name has a different role than expected. None

Methods

RelationRoleMismatchError. __init__( self , relation_name: str , expected_relation_role: RelationRole , actual_relation_role: RelationRole )

class RequestEvent

Description

Event emitted when a remote requests a tracing endpoint. None

Methods

RequestEvent. requested_receivers( self )

Description

List of receiver protocols that have been requested. None

class BrokenEvent

Description

Event emitted when a relation on tracing is broken. None

class TracingEndpointProviderEvents

Description

TracingEndpointProvider events. None

class TracingEndpointProvider

Description

Class representing a trace receiver service. None

Methods

TracingEndpointProvider. __init__( self , charm: CharmBase , external_url , relation_name: str )

Initialize.

Arguments

charm

a CharmBase instance that manages this instance of the Tempo service.

external_url

external address of the node hosting the tempo server, if an ingress is present.

relation_name

an optional string name of the relation between charm and the Tempo charmed service. The default is "tracing".

TracingEndpointProvider. is_requirer_ready( self , relation: Relation )

Description

Attempt to determine if requirer has already populated app data. None

TracingEndpointProvider. requested_protocols( self )

Description

All receiver protocols that have been requested by our related apps. None

TracingEndpointProvider. relations( self )

Description

All relations active on this endpoint. None

TracingEndpointProvider. publish_receivers( self , receivers )

Description

Let all requirers know that these receivers are active and listening. None

class EndpointRemovedEvent

Description

Event representing a change in one of the receiver endpoints. None

class EndpointChangedEvent

Description

Event representing a change in one of the receiver endpoints. None

Methods

EndpointChangedEvent. receivers( self )

Description

Cast receivers back from dict. None

class TracingEndpointRequirerEvents

Description

TracingEndpointRequirer events. None

class TracingEndpointRequirer

Description

A tracing endpoint for Tempo. None

Methods

TracingEndpointRequirer. __init__( self , charm: CharmBase , relation_name: str , protocols )

Construct a tracing requirer for a Tempo charm.

Arguments

charm

a CharmBase object that manages this TracingEndpointRequirer object. Typically, this is self in the instantiating class.

relation_name

an optional string name of the relation between charm and the Tempo charmed service. The default is "tracing". It is strongly advised not to change the default, so that people deploying your charm will have a consistent experience with all other charms that provide tracing endpoints.

protocols

optional list of protocols that the charm intends to send traces with. The provider will enable receivers for these and only these protocols, so be sure to enable all protocols the charm or its workload are going to need.

Description

If your application supports pushing traces to a distributed tracing backend, the TracingEndpointRequirer object enables your charm to easily access endpoint information exchanged over a tracing relation interface.

TracingEndpointRequirer. request_protocols( self , protocols , relation )

Description

Publish the list of protocols which the provider should activate. None

TracingEndpointRequirer. relations( self )

Description

The tracing relations associated with this endpoint. None

TracingEndpointRequirer. is_ready( self , relation )

Description

Is this endpoint ready? None

TracingEndpointRequirer. get_all_endpoints( self , relation )

Description

Unmarshalled relation data. None

TracingEndpointRequirer. get_endpoint( self , protocol: ReceiverProtocol , relation )

Receiver endpoint for the given protocol.

Description

It could happen that this function gets called before the provider publishes the endpoints. In such a scenario, if a non-leader unit calls this function, a permission denied exception will be raised due to restricted access. To prevent this, this function needs to be guarded by the is_ready check.

Raises: ProtocolNotRequestedError: If the charm unit is the leader unit and attempts to obtain an endpoint for a protocol it did not request.

def charm_tracing_config(
    endpoint_requirer: TracingEndpointRequirer,
    cert_path
)

Return the charm_tracing config you likely want.

Description

If no endpoint is provided: disable charm tracing. If https endpoint is provided but cert_path is not found on disk: disable charm tracing. If https endpoint is provided and cert_path is None: ERROR Else: proceed with charm tracing (with or without tls, as appropriate)

Usage: If you are using charm_tracing >= v1.9:

from lib.charms.tempo_coordinator_k8s.v0.charm_tracing import trace_charm from lib.charms.tempo_coordinator_k8s.v0.tracing import charm_tracing_config @trace_charm(tracing_endpoint="my_endpoint", cert_path="cert_path") class MyCharm(...): _cert_path = "/path/to/cert/on/charm/container.crt" def init(self, ...): self.tracing = TracingEndpointRequirer(...) self.my_endpoint, self.cert_path = charm_tracing_config( ... self.tracing, self._cert_path)

If you are using charm_tracing < v1.9:

from lib.charms.tempo_coordinator_k8s.v0.charm_tracing import trace_charm from lib.charms.tempo_coordinator_k8s.v0.tracing import charm_tracing_config @trace_charm(tracing_endpoint="my_endpoint", cert_path="cert_path") class MyCharm(...): _cert_path = "/path/to/cert/on/charm/container.crt" def init(self, ...): self.tracing = TracingEndpointRequirer(...) self._my_endpoint, self._cert_path = charm_tracing_config( ... self.tracing, self._cert_path) @property def my_endpoint(self): return self._my_endpoint @property def cert_path(self): return self._cert_path