# otel-extensions-python: OpenTelemetry Extensions for Python
OpenTelemetry Extensions for Python is a collection of helper classes, functions, and decorators to facilitate the use of the
[OpenTelemetry Python API & SDK packages](https://opentelemetry.io/docs/instrumentation/python/)
## Version Support
Python >= 3.6
## Installation
### pip install
You can install through pip using:
```sh
pip install otel-extensions
```
(you may need to run `pip` with root permission: `sudo pip install otel-extensions`)
### Setuptools
Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)
## Features
### Tracer Provider Initialization
```python
from otel_extensions import init_telemetry_provider, TelemetryOptions
# Provide options for telemetry provider
# Alternatively, any of the following options can be specified through
# environment variables with the equivalent name
options = TelemetryOptions(
# OTLP receiver endpoint
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317/",
# CA bundle for TLS verification of endpoint (if endpoint scheme is https)
OTEL_EXPORTER_OTLP_CERTIFICATE="/path/to/ca/bundle",
# protocol for OTLP receiver (supported: gprc | http/protobuf | custom)
OTEL_EXPORTER_OTLP_PROTOCOL="grpc",
# Custom span exporter class name (needed if protocol set to 'custom')
OTEL_EXPORTER_CUSTOM_SPAN_EXPORTER_TYPE="pkg.ClassName",
# Name of service
OTEL_SERVICE_NAME="My Service",
# Processor type
# batch: use BatchSpanProcessor
# simple: use SimpleSpanProcessor
OTEL_PROCESSOR_TYPE="batch",
# Optional parent span id. Will be injected into current context
TRACEPARENT="001233454656...."
)
# Initialize the global tracer provider
init_telemetry_provider(options)
```
### Instrumentation Decorator
You can use the `@instrumented` decorator to automatically wrap a span around a function or method.
(As of version 0.2.0, the decorator can support coroutine functions defined as `async def` as well as normal functions)
```python
from otel_extensions import init_telemetry_provider, instrumented
import asyncio
async def main():
foo()
await async_foo()
@instrumented
def foo():
"""Creates a span named 'foo'"""
bar()
@instrumented(span_name="custom span name")
def bar():
"""Creates a span named 'custom span name'"""
print("Hello World")
@instrumented(span_attributes={"attr1": "val1", "attr2": "val2"})
def fn_with_attrs():
"""Creates a span named 'fn_with_attrs' and sets key/value pairs
from `span_attributes` as span attributes"""
print("Hello World")
@instrumented
async def async_foo():
"""Creates a span named 'async_foo'"""
await async_bar()
@instrumented(span_name="custom span name")
async def async_bar():
"""Creates a span named 'custom span name'"""
print("Hello World")
@instrumented(span_name="custom span name")
async def async_bar():
"""Creates a span named 'custom span name'"""
print("Hello World")
@instrumented(span_attributes={"attr1": "val1", "attr2": "val2"})
async def async_fn_with_attrs():
"""Creates a span named 'async_fn_with_attrs' and sets key/value pairs
from `span_attributes` as span attributes"""
print("Hello World")
if __name__ == '__main__':
# init telemetry provider (using options from environment variables)
init_telemetry_provider()
asyncio.run(main())
```
#### Conditional span creation
If the OTEL_PROCESS_MODULES environment variable is set, the `@instrumented` decorator will only create a span if the module of the decorated function is in the list of modules specified in the environment variable.
```python
import os
from otel_extensions import instrumented
os.environ["OTEL_PROCESS_MODULES"] = "module1,module2"
@instrumented
def foo():
"""
Would create a span named 'foo', but only if the module of this function
were named 'module1' or 'module2'
"""
bar()
```
### Trace Context helper class
The `TraceContextCarrier` class is useful when propagating context across process or thread boundaries
```python
from otel_extensions import TraceContextCarrier
from threading import Thread
def main_program():
...
# capture current context
ctx = TraceContextCarrier()
thread = Thread(thread_func, args=(ctx))
thread.start()
...
def thread_func(ctx: TraceContextCarrier):
# attach to context stored in ctx
ctx.attach()
...
```
Also, the `TraceContextCarrier` class can attach to context stored in the `TRACEPARENT` environment variable.
Note that this is done automatically when calling the `init_telemetry_provider()` function.
```python
from otel_extensions import TraceContextCarrier
TraceContextCarrier.attach_from_env()
```
`TraceContextCarrier` can also inject the current context into the `TRACEPARENT` environment variable.
This is useful for context propagation when using `Popen` to create a subprocess
```python
from otel_extensions import TraceContextCarrier
from subprocess import Popen
TraceContextCarrier.inject_to_env()
process = Popen(...)
```
### Log messages as events
The `TraceEventLogHandler` class is a `logging.Handler` class that creates events for any log message that occurs in a span.
```python
from otel_extensions import TraceEventLogHandler, init_telemetry_provider, get_tracer
import logging
init_telemetry_provider()
logging.basicConfig()
logging.getLogger(__name__).addHandler(TraceEventLogHandler())
with get_tracer(__name__).start_as_current_span("foo") as span:
logging.getLogger(__name__).warning("Some log message")
# 'Some Log message' will be created as an event in 'span',
# as if you had called
# span.add_event('Some Log message')
```
Raw data
{
"_id": null,
"home_page": null,
"name": "otel-extensions",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "Joe Savage <joe.savage@gmail.com>",
"keywords": "otel, opentelemetry, debug",
"author": null,
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/dd/4e/5ee78ffa054e5ba1fc9ea91a25a09befa5264c9438a3658685ae94cdb28a/otel_extensions-1.1.0.tar.gz",
"platform": "any",
"description": "# otel-extensions-python: OpenTelemetry Extensions for Python\r\nOpenTelemetry Extensions for Python is a collection of helper classes, functions, and decorators to facilitate the use of the \r\n[OpenTelemetry Python API & SDK packages](https://opentelemetry.io/docs/instrumentation/python/)\r\n\r\n\r\n## Version Support\r\n\r\nPython >= 3.6\r\n\r\n## Installation\r\n### pip install\r\n\r\nYou can install through pip using:\r\n\r\n```sh\r\npip install otel-extensions\r\n```\r\n(you may need to run `pip` with root permission: `sudo pip install otel-extensions`)\r\n\r\n\r\n### Setuptools\r\n\r\nInstall via [Setuptools](http://pypi.python.org/pypi/setuptools).\r\n\r\n```sh\r\npython setup.py install --user\r\n```\r\n(or `sudo python setup.py install` to install the package for all users)\r\n\r\n\r\n\r\n## Features\r\n\r\n### Tracer Provider Initialization\r\n\r\n```python\r\nfrom otel_extensions import init_telemetry_provider, TelemetryOptions\r\n\r\n# Provide options for telemetry provider\r\n# Alternatively, any of the following options can be specified through\r\n# environment variables with the equivalent name\r\noptions = TelemetryOptions(\r\n # OTLP receiver endpoint\r\n OTEL_EXPORTER_OTLP_ENDPOINT=\"http://localhost:4317/\",\r\n # CA bundle for TLS verification of endpoint (if endpoint scheme is https)\r\n OTEL_EXPORTER_OTLP_CERTIFICATE=\"/path/to/ca/bundle\",\r\n # protocol for OTLP receiver (supported: gprc | http/protobuf | custom)\r\n OTEL_EXPORTER_OTLP_PROTOCOL=\"grpc\",\r\n # Custom span exporter class name (needed if protocol set to 'custom')\r\n OTEL_EXPORTER_CUSTOM_SPAN_EXPORTER_TYPE=\"pkg.ClassName\",\r\n # Name of service\r\n OTEL_SERVICE_NAME=\"My Service\",\r\n # Processor type\r\n # batch: use BatchSpanProcessor\r\n # simple: use SimpleSpanProcessor\r\n OTEL_PROCESSOR_TYPE=\"batch\",\r\n # Optional parent span id. Will be injected into current context\r\n TRACEPARENT=\"001233454656....\"\r\n)\r\n# Initialize the global tracer provider\r\ninit_telemetry_provider(options)\r\n```\r\n\r\n### Instrumentation Decorator\r\nYou can use the `@instrumented` decorator to automatically wrap a span around a function or method.\r\n(As of version 0.2.0, the decorator can support coroutine functions defined as `async def` as well as normal functions)\r\n\r\n```python\r\nfrom otel_extensions import init_telemetry_provider, instrumented\r\nimport asyncio\r\n\r\nasync def main():\r\n foo()\r\n await async_foo()\r\n \r\n@instrumented\r\ndef foo():\r\n \"\"\"Creates a span named 'foo'\"\"\"\r\n bar()\r\n\r\n@instrumented(span_name=\"custom span name\")\r\ndef bar():\r\n \"\"\"Creates a span named 'custom span name'\"\"\"\r\n print(\"Hello World\")\r\n \r\n@instrumented(span_attributes={\"attr1\": \"val1\", \"attr2\": \"val2\"})\r\ndef fn_with_attrs():\r\n \"\"\"Creates a span named 'fn_with_attrs' and sets key/value pairs\r\n from `span_attributes` as span attributes\"\"\"\r\n print(\"Hello World\")\r\n\r\n@instrumented\r\nasync def async_foo():\r\n \"\"\"Creates a span named 'async_foo'\"\"\"\r\n await async_bar()\r\n\r\n@instrumented(span_name=\"custom span name\")\r\nasync def async_bar():\r\n \"\"\"Creates a span named 'custom span name'\"\"\"\r\n print(\"Hello World\")\r\n \r\n@instrumented(span_name=\"custom span name\")\r\nasync def async_bar():\r\n \"\"\"Creates a span named 'custom span name'\"\"\"\r\n print(\"Hello World\")\r\n \r\n@instrumented(span_attributes={\"attr1\": \"val1\", \"attr2\": \"val2\"})\r\nasync def async_fn_with_attrs():\r\n \"\"\"Creates a span named 'async_fn_with_attrs' and sets key/value pairs\r\n from `span_attributes` as span attributes\"\"\"\r\n print(\"Hello World\")\r\n \r\nif __name__ == '__main__':\r\n # init telemetry provider (using options from environment variables)\r\n init_telemetry_provider()\r\n asyncio.run(main())\r\n\r\n```\r\n\r\n#### Conditional span creation\r\nIf the OTEL_PROCESS_MODULES environment variable is set, the `@instrumented` decorator will only create a span if the module of the decorated function is in the list of modules specified in the environment variable.\r\n\r\n```python\r\nimport os\r\nfrom otel_extensions import instrumented\r\n\r\nos.environ[\"OTEL_PROCESS_MODULES\"] = \"module1,module2\"\r\n \r\n@instrumented\r\ndef foo():\r\n \"\"\"\r\n Would create a span named 'foo', but only if the module of this function \r\n were named 'module1' or 'module2'\r\n \"\"\"\r\n bar()\r\n```\r\n\r\n### Trace Context helper class\r\nThe `TraceContextCarrier` class is useful when propagating context across process or thread boundaries\r\n\r\n```python\r\nfrom otel_extensions import TraceContextCarrier\r\nfrom threading import Thread\r\n\r\n\r\ndef main_program():\r\n ...\r\n # capture current context\r\n ctx = TraceContextCarrier()\r\n thread = Thread(thread_func, args=(ctx))\r\n thread.start()\r\n ...\r\n\r\ndef thread_func(ctx: TraceContextCarrier):\r\n # attach to context stored in ctx\r\n ctx.attach()\r\n ...\r\n```\r\n\r\nAlso, the `TraceContextCarrier` class can attach to context stored in the `TRACEPARENT` environment variable.\r\nNote that this is done automatically when calling the `init_telemetry_provider()` function.\r\n\r\n```python\r\nfrom otel_extensions import TraceContextCarrier\r\n\r\nTraceContextCarrier.attach_from_env()\r\n```\r\n\r\n`TraceContextCarrier` can also inject the current context into the `TRACEPARENT` environment variable.\r\nThis is useful for context propagation when using `Popen` to create a subprocess\r\n```python\r\nfrom otel_extensions import TraceContextCarrier\r\nfrom subprocess import Popen\r\n\r\nTraceContextCarrier.inject_to_env()\r\nprocess = Popen(...)\r\n```\r\n\r\n### Log messages as events\r\nThe `TraceEventLogHandler` class is a `logging.Handler` class that creates events for any log message that occurs in a span.\r\n\r\n```python\r\nfrom otel_extensions import TraceEventLogHandler, init_telemetry_provider, get_tracer\r\nimport logging\r\n\r\ninit_telemetry_provider()\r\n\r\nlogging.basicConfig()\r\nlogging.getLogger(__name__).addHandler(TraceEventLogHandler())\r\n\r\nwith get_tracer(__name__).start_as_current_span(\"foo\") as span:\r\n logging.getLogger(__name__).warning(\"Some log message\")\r\n # 'Some Log message' will be created as an event in 'span',\r\n # as if you had called\r\n # span.add_event('Some Log message')\r\n\r\n```\r\n\r\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Python extensions for OpenTelemetry",
"version": "1.1.0",
"project_urls": {
"Homepage": "https://github.com/s4v4g3/otel-extensions-python",
"Source": "https://github.com/s4v4g3/otel-extensions-python",
"Tracker": "https://github.com/s4v4g3/otel-extensions-python/issues"
},
"split_keywords": [
"otel",
" opentelemetry",
" debug"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e9dc56211b810e066da30ffa7df0ef240fba8379fc52304db127c7accbe56a45",
"md5": "b1c4794a694e66f2ffc417dbdadbf8cf",
"sha256": "695df880d1cbf6df9274c5e414728f9781a5fabd9c44b865a92efe056d724f2c"
},
"downloads": -1,
"filename": "otel_extensions-1.1.0-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "b1c4794a694e66f2ffc417dbdadbf8cf",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.8",
"size": 11826,
"upload_time": "2024-10-21T17:36:20",
"upload_time_iso_8601": "2024-10-21T17:36:20.476008Z",
"url": "https://files.pythonhosted.org/packages/e9/dc/56211b810e066da30ffa7df0ef240fba8379fc52304db127c7accbe56a45/otel_extensions-1.1.0-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "dd4e5ee78ffa054e5ba1fc9ea91a25a09befa5264c9438a3658685ae94cdb28a",
"md5": "2bda14aeca82dabd5b5066c2e3f1c2b6",
"sha256": "20ff10fb360d9bf1d8498f3c698e384ee81b07331206754b814d7f3fc1c71ed2"
},
"downloads": -1,
"filename": "otel_extensions-1.1.0.tar.gz",
"has_sig": false,
"md5_digest": "2bda14aeca82dabd5b5066c2e3f1c2b6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 14972,
"upload_time": "2024-10-21T17:36:22",
"upload_time_iso_8601": "2024-10-21T17:36:22.120940Z",
"url": "https://files.pythonhosted.org/packages/dd/4e/5ee78ffa054e5ba1fc9ea91a25a09befa5264c9438a3658685ae94cdb28a/otel_extensions-1.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-21 17:36:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "s4v4g3",
"github_project": "otel-extensions-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "opentelemetry-api",
"specs": []
},
{
"name": "opentelemetry-sdk",
"specs": []
}
],
"tox": true,
"lcname": "otel-extensions"
}