opentelemetry.io/content/en/docs/instrumentation/python/manual.md

200 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Manual Instrumentation
linkTitle: Manual
weight: 3
---
Manual instrumentation is the process of adding observability code to your
application.
## Initializing tracing
To start tracing, you'll need to initialize a `TracerProvider`.
First, ensure you have the API and SDK packages:
```
pip install opentelemetry-api
pip install opentelemetry-sdk
```
Next, initialize a `TracerProvider` and set it for your app:
```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
ConsoleSpanExporter,
)
provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
```
With a call to `get_tracer`, you can create spans.
## Creating spans
To create a span, you'll typically want it to be started as the current span.
```python
def do_work():
with tracer.start_as_current_span("span-name") as span:
# do some work that 'span' will track
print("doing some work...")
# When the 'with' block goes out of scope, 'span' is closed for you
```
You can also use `start_span` to create a span without making it the current
span. This is usually done to track concurrent or asynchronous operations.
## Creating nested spans
If you have a distinct sub-operation you'd like to track as a part of another
one, you can create spans to represent the relationship:
```python
def do_work():
with tracer.start_as_current_span("parent") as parent:
# do some work that 'parent' tracks
print("doing some work...")
# Create a nested span to track nested work
with tracer.start_as_current_span("child") as child:
# do some work that 'child' tracks
print("doing some nested work...")
# the nested span is closed when it's out of scope
# This span is also closed when it goes out of scope
```
When you view spans in a trace visualization tool, `child` will be tracked as a
nested span under `parent`.
## Creating spans with decorators
It's common to have a single span track the execution of an entire function. In
that scenario, there is a decorator you can use to reduce code:
```python
@tracer.start_as_current_span("do_work")
def do_work():
print("doing some work...")
```
Use of the decorator is equivalent to creating the span inside `do_work()` and
ending it when `do_work()` is finished.
To use the decorator, you must have a `tracer` instance available global to your
function declaration.
If you need to add [attributes](#add-attributes-to-a-span),
[events](#adding-events), or [links](#adding-links) then it's less convenient to
use a decorator.
## Get the current span
Sometimes it's helpful to access whatever the current span is at a point in time
so that you can enrich it with more information.
```python
from opentelemetry import trace
current_span = trace.get_current_span()
# enrich 'current_span' with some information
```
## Add attributes to a span
Attributes let you attach key/value pairs to a span so it carries more
information about the current operation that it's tracking.
```python
from opentelemetry import trace
current_span = trace.get_current_span()
current_span.set_attribute("operation.value", 1)
current_span.set_attribute("operation.name", "Saying hello!")
current_span.set_attribute("operation.other-stuff", [1, 2, 3])
```
## Adding events
An event is a human-readable message on a span that represents "something
happening" during its lifetime. You can think of it as a primitive log.
```python
from opentelemetry import trace
current_span = trace.get_current_span()
current_span.add_event("Gonna try it!")
# Do the thing
current_span.add_event("Did it!")
```
## Adding links
A span can be created with zero or more span links that causally link it to
another span. A link needs a span context to be created.
```python
from opentelemetry import trace
ctx = trace.get_current_span().get_span_context()
link_from_current = trace.Link(ctx)
with tracer.start_as_current_span("new-span", links=[link_from_current]) as new_span:
# do something that 'new_span' tracks
# The link in 'new_span' casually associated it with the previous one,
# but it is not a child span.
```
## Set span status
A status can be set on a span, 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 dont set `StatusCode.OK` on
successfully-completed spans.
The status can be set at any time before the span is finished:
```python
from opentelemetry import trace
current_span = trace.get_current_span()
try:
# something that might fail
except:
current_span.set_status(StatusCode.ERROR)
```
## Record exceptions in spans
It can be a good idea to record exceptions when they happen. Its recommended to
do this in conjunction with setting [span status](#set-span-status).
```python
from opentelemetry import trace
current_span = trace.get_current_span()
try:
# something that might fail
# Consider catching a more specific exception in your code
except Exception as ex:
current_span.set_status(StatusCode.ERROR)
current_span.record_exception(ex)
```