rebrandly-otel 0.2.16__py3-none-any.whl → 0.2.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rebrandly-otel might be problematic. Click here for more details.
- rebrandly_otel/span_attributes_processor.py +106 -0
- rebrandly_otel/traces.py +4 -0
- {rebrandly_otel-0.2.16.dist-info → rebrandly_otel-0.2.19.dist-info}/METADATA +74 -9
- {rebrandly_otel-0.2.16.dist-info → rebrandly_otel-0.2.19.dist-info}/RECORD +7 -6
- {rebrandly_otel-0.2.16.dist-info → rebrandly_otel-0.2.19.dist-info}/WHEEL +0 -0
- {rebrandly_otel-0.2.16.dist-info → rebrandly_otel-0.2.19.dist-info}/licenses/LICENSE +0 -0
- {rebrandly_otel-0.2.16.dist-info → rebrandly_otel-0.2.19.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Span Attributes Processor for Rebrandly OTEL SDK
|
|
3
|
+
Automatically adds attributes from OTEL_SPAN_ATTRIBUTES environment variable to all spans
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from opentelemetry.context import Context
|
|
9
|
+
from opentelemetry.sdk.trace import ReadableSpan, Span
|
|
10
|
+
from opentelemetry.sdk.trace.export import SpanProcessor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SpanAttributesProcessor(SpanProcessor):
|
|
14
|
+
"""
|
|
15
|
+
Span processor that automatically adds attributes from OTEL_SPAN_ATTRIBUTES
|
|
16
|
+
environment variable to all spans at creation time.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
"""Initialize the processor and parse OTEL_SPAN_ATTRIBUTES."""
|
|
21
|
+
self.name = 'SpanAttributesProcessor'
|
|
22
|
+
self.span_attributes = self._parse_span_attributes()
|
|
23
|
+
|
|
24
|
+
# Log parsed attributes in debug mode
|
|
25
|
+
if os.environ.get('OTEL_DEBUG', 'false').lower() == 'true' and self.span_attributes:
|
|
26
|
+
print(f'[SpanAttributesProcessor] Parsed OTEL_SPAN_ATTRIBUTES: {self.span_attributes}')
|
|
27
|
+
|
|
28
|
+
def _parse_span_attributes(self) -> dict:
|
|
29
|
+
"""
|
|
30
|
+
Parse OTEL_SPAN_ATTRIBUTES environment variable.
|
|
31
|
+
Format: key1=value1,key2=value2
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Dictionary of parsed attributes as key-value pairs
|
|
35
|
+
"""
|
|
36
|
+
attributes = {}
|
|
37
|
+
otel_span_attrs = os.environ.get('OTEL_SPAN_ATTRIBUTES', None)
|
|
38
|
+
|
|
39
|
+
if not otel_span_attrs or otel_span_attrs.strip() == '':
|
|
40
|
+
return attributes
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
pairs = otel_span_attrs.split(',')
|
|
44
|
+
for attr in pairs:
|
|
45
|
+
trimmed_attr = attr.strip()
|
|
46
|
+
if trimmed_attr and '=' in trimmed_attr:
|
|
47
|
+
# Split on first '=' only, in case value contains '='
|
|
48
|
+
key, value = trimmed_attr.split('=', 1)
|
|
49
|
+
key = key.strip()
|
|
50
|
+
value = value.strip()
|
|
51
|
+
if key:
|
|
52
|
+
attributes[key] = value
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print(f'[SpanAttributesProcessor] Warning: Invalid OTEL_SPAN_ATTRIBUTES value: {e}')
|
|
55
|
+
|
|
56
|
+
return attributes
|
|
57
|
+
|
|
58
|
+
def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Called when a span is started.
|
|
61
|
+
Adds configured attributes to the span.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
span: The span that was just started
|
|
65
|
+
parent_context: The parent context (optional)
|
|
66
|
+
"""
|
|
67
|
+
try:
|
|
68
|
+
# Add all parsed attributes to the span
|
|
69
|
+
if self.span_attributes:
|
|
70
|
+
for key, value in self.span_attributes.items():
|
|
71
|
+
span.set_attribute(key, value)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
# Fail silently to avoid breaking the entire tracing pipeline
|
|
74
|
+
# Log only in debug mode to avoid noise
|
|
75
|
+
if os.environ.get('OTEL_DEBUG', 'false').lower() == 'true':
|
|
76
|
+
print(f'[SpanAttributesProcessor] Error processing span: {e}')
|
|
77
|
+
|
|
78
|
+
def on_end(self, span: ReadableSpan) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Called when a span is ended.
|
|
81
|
+
No-op for this processor.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
span: The span that was just ended
|
|
85
|
+
"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
def shutdown(self) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Shutdown the processor.
|
|
91
|
+
No-op for this processor.
|
|
92
|
+
"""
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
96
|
+
"""
|
|
97
|
+
Force flush the processor.
|
|
98
|
+
No-op for this processor.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
timeout_millis: Maximum time to wait for flush in milliseconds
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Always returns True as there's nothing to flush
|
|
105
|
+
"""
|
|
106
|
+
return True
|
rebrandly_otel/traces.py
CHANGED
|
@@ -12,6 +12,7 @@ from opentelemetry.sdk.trace.export import (
|
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
from .otel_utils import *
|
|
15
|
+
from .span_attributes_processor import SpanAttributesProcessor
|
|
15
16
|
|
|
16
17
|
class RebrandlyTracer:
|
|
17
18
|
"""Wrapper for OpenTelemetry tracing with Rebrandly-specific features."""
|
|
@@ -26,6 +27,9 @@ class RebrandlyTracer:
|
|
|
26
27
|
# Create provider with resource
|
|
27
28
|
self._provider = TracerProvider(resource=create_resource())
|
|
28
29
|
|
|
30
|
+
# Add span attributes processor to automatically add OTEL_SPAN_ATTRIBUTES to all spans
|
|
31
|
+
self._provider.add_span_processor(SpanAttributesProcessor())
|
|
32
|
+
|
|
29
33
|
# Add console exporter for local debugging
|
|
30
34
|
if is_otel_debug():
|
|
31
35
|
console_exporter = ConsoleSpanExporter()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rebrandly_otel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.19
|
|
4
4
|
Summary: Python OTEL wrapper by Rebrandly
|
|
5
5
|
Home-page: https://github.com/rebrandly/rebrandly-otel-python
|
|
6
6
|
Author: Antonio Romano
|
|
@@ -51,14 +51,16 @@ pip install rebrandly-otel
|
|
|
51
51
|
|
|
52
52
|
The SDK is configured through environment variables:
|
|
53
53
|
|
|
54
|
-
| Variable | Description | Default
|
|
55
|
-
|
|
56
|
-
| `OTEL_SERVICE_NAME` | Service identifier | `default-service-python`
|
|
57
|
-
| `OTEL_SERVICE_VERSION` | Service version | `1.0.0`
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
54
|
+
| Variable | Description | Default |
|
|
55
|
+
|------------------------------------|-------------|---------------------------------|
|
|
56
|
+
| `OTEL_SERVICE_NAME` | Service identifier | `default-service-python` |
|
|
57
|
+
| `OTEL_SERVICE_VERSION` | Service version | `1.0.0` |
|
|
58
|
+
| `OTEL_SERVICE_APPLICATION` | Application namespace (groups multiple services under one application) | Fallback to `OTEL_SERVICE_NAME` |
|
|
59
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint | `None` |
|
|
60
|
+
| `OTEL_DEBUG` | Enable console debugging | `false` |
|
|
61
|
+
| `OTEL_SPAN_ATTRIBUTES` | Attributes automatically added to all spans (format: `key1=value1,key2=value2`) | `None` |
|
|
62
|
+
| `BATCH_EXPORT_TIME_MILLIS` | Batch export interval | `100` |
|
|
63
|
+
| `ENV` or `ENVIRONMENT` or `NODE_ENV` | Deployment environment | `local` |
|
|
62
64
|
|
|
63
65
|
## Core Components
|
|
64
66
|
|
|
@@ -146,6 +148,67 @@ Lambda spans automatically include:
|
|
|
146
148
|
- `cloud.provider`: Always "aws" for Lambda
|
|
147
149
|
- `cloud.platform`: Always "aws_lambda" for Lambda
|
|
148
150
|
|
|
151
|
+
## Automatic Span Attributes
|
|
152
|
+
|
|
153
|
+
The SDK supports automatically adding custom attributes to all spans via the `OTEL_SPAN_ATTRIBUTES` environment variable. This is useful for adding metadata that applies to all telemetry in a service, such as team ownership, deployment environment, or version information.
|
|
154
|
+
|
|
155
|
+
### Configuration
|
|
156
|
+
|
|
157
|
+
Set the `OTEL_SPAN_ATTRIBUTES` environment variable with a comma-separated list of key-value pairs:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
export OTEL_SPAN_ATTRIBUTES="team=backend,environment=production,version=1.2.3"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Behavior
|
|
164
|
+
|
|
165
|
+
- **Universal Application**: Attributes are added to ALL spans, including:
|
|
166
|
+
- Manually created spans (`tracer.start_span()`, `tracer.start_as_current_span()`)
|
|
167
|
+
- Lambda handler spans (`@lambda_handler`)
|
|
168
|
+
- AWS message handler spans (`@aws_message_handler`)
|
|
169
|
+
- Flask/FastAPI middleware spans
|
|
170
|
+
- Auto-instrumented spans (database queries, HTTP requests, etc.)
|
|
171
|
+
|
|
172
|
+
- **Format**: Same as `OTEL_RESOURCE_ATTRIBUTES` - comma-separated `key=value` pairs
|
|
173
|
+
- **Value Handling**: Supports values containing `=` characters (e.g., URLs)
|
|
174
|
+
- **Whitespace**: Leading/trailing whitespace is automatically trimmed
|
|
175
|
+
|
|
176
|
+
### Example
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import os
|
|
180
|
+
|
|
181
|
+
# Set environment variable
|
|
182
|
+
os.environ['OTEL_SPAN_ATTRIBUTES'] = "team=backend,service.owner=platform-team,deployment.region=us-east-1"
|
|
183
|
+
|
|
184
|
+
# Initialize SDK
|
|
185
|
+
from rebrandly_otel import otel, logger
|
|
186
|
+
|
|
187
|
+
# Create any span - attributes are added automatically
|
|
188
|
+
with otel.span('my-operation'):
|
|
189
|
+
logger.info('Processing request')
|
|
190
|
+
# The span will include:
|
|
191
|
+
# - team: "backend"
|
|
192
|
+
# - service.owner: "platform-team"
|
|
193
|
+
# - deployment.region: "us-east-1"
|
|
194
|
+
# ... plus any other attributes you set manually
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Use Cases
|
|
198
|
+
|
|
199
|
+
- **Team/Ownership Tagging**: `team=backend,owner=john@example.com`
|
|
200
|
+
- **Environment Metadata**: `environment=production,region=us-east-1,availability_zone=us-east-1a`
|
|
201
|
+
- **Version Tracking**: `version=1.2.3,build=12345,commit=abc123def`
|
|
202
|
+
- **Cost Attribution**: `cost_center=engineering,project=customer-api`
|
|
203
|
+
- **Multi-Tenancy**: `tenant=acme-corp,customer_tier=enterprise`
|
|
204
|
+
|
|
205
|
+
### Difference from OTEL_RESOURCE_ATTRIBUTES
|
|
206
|
+
|
|
207
|
+
- **OTEL_RESOURCE_ATTRIBUTES**: Service-level metadata (set once, applies to the entire service instance)
|
|
208
|
+
- **OTEL_SPAN_ATTRIBUTES**: Span-level metadata (added to each individual span at creation time)
|
|
209
|
+
|
|
210
|
+
Both use the same format but serve different purposes in the OpenTelemetry data model.
|
|
211
|
+
|
|
149
212
|
### Exception Handling
|
|
150
213
|
|
|
151
214
|
Spans automatically capture exceptions with:
|
|
@@ -521,6 +584,7 @@ pytest tests/test_usage.py -v
|
|
|
521
584
|
pytest tests/test_pymysql_instrumentation.py -v
|
|
522
585
|
pytest tests/test_metrics_and_logs.py -v
|
|
523
586
|
pytest tests/test_decorators.py -v
|
|
587
|
+
pytest tests/test_span_attributes_processor.py -v
|
|
524
588
|
```
|
|
525
589
|
|
|
526
590
|
Run with coverage:
|
|
@@ -537,6 +601,7 @@ The test suite includes:
|
|
|
537
601
|
- **PyMySQL instrumentation tests** (`test_pymysql_instrumentation.py`): Database connection instrumentation, query tracing, helper functions
|
|
538
602
|
- **Metrics and logs tests** (`test_metrics_and_logs.py`): Custom metrics creation (counter, histogram, gauge), logging levels (info, warning, debug, error)
|
|
539
603
|
- **Decorators tests** (`test_decorators.py`): Lambda handler decorator, AWS message handler decorator, traces decorator, aws_message_span context manager
|
|
604
|
+
- **Span attributes processor tests** (`test_span_attributes_processor.py`): Automatic span attributes from OTEL_SPAN_ATTRIBUTES (31 tests)
|
|
540
605
|
|
|
541
606
|
## License
|
|
542
607
|
|
|
@@ -7,9 +7,10 @@ rebrandly_otel/metrics.py,sha256=jZPygTY7vie33sadXc7P1DwLTKe9tJvAWSZuGHW1xQg,774
|
|
|
7
7
|
rebrandly_otel/otel_utils.py,sha256=wbtr2_eZTRHmgqo6PY6nCe81zdyQXo9bpDd9D2NehrM,6028
|
|
8
8
|
rebrandly_otel/pymysql_instrumentation.py,sha256=lS_V5DcsnpQ3f2PoNqeM7t3Jyiew2KNURM9iILfz8sM,6477
|
|
9
9
|
rebrandly_otel/rebrandly_otel.py,sha256=8EArZTkeqV0IWLrgKH4vZzY-6VhJBNRp4_c99mpjJNw,22785
|
|
10
|
-
rebrandly_otel/
|
|
11
|
-
rebrandly_otel
|
|
12
|
-
rebrandly_otel-0.2.
|
|
13
|
-
rebrandly_otel-0.2.
|
|
14
|
-
rebrandly_otel-0.2.
|
|
15
|
-
rebrandly_otel-0.2.
|
|
10
|
+
rebrandly_otel/span_attributes_processor.py,sha256=eB5oeHwNw4gtD3opQYOJVOq7VQYRj2YEv4oL7BV0t9Q,3609
|
|
11
|
+
rebrandly_otel/traces.py,sha256=Y7WE17vGYvetoxzjUBmAEnwI9r7GBMFffBww4zcnFbk,7402
|
|
12
|
+
rebrandly_otel-0.2.19.dist-info/licenses/LICENSE,sha256=KMXHvTwP62S2q-SG7CFfMU_09rUwxiqlM0izaYGdcgY,1103
|
|
13
|
+
rebrandly_otel-0.2.19.dist-info/METADATA,sha256=D5OUsMGWasrFLV0DhH5LDDQNTYyv1vsIz_d_cZUifKo,18807
|
|
14
|
+
rebrandly_otel-0.2.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
rebrandly_otel-0.2.19.dist-info/top_level.txt,sha256=26PSC1gjVUl8tTH5QfKbFevjVV4E2yojoukEfiTScvM,15
|
|
16
|
+
rebrandly_otel-0.2.19.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|