Skip to content

Commit ce12b1b

Browse files
Mv example to docstring; lint
1 parent 4b0c6ed commit ce12b1b

File tree

4 files changed

+74
-78
lines changed

4 files changed

+74
-78
lines changed

opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/__init__.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,64 @@
1313
# limitations under the License.
1414

1515
"""
16-
Labeler that supports per-request custom attribute addition to web framework
17-
instrumentor-originating OpenTelemetry metrics.
16+
OpenTelemetry Labeler
17+
=====================
18+
19+
The labeler utility provides a way to add custom attributes to metrics generated by OpenTelemetry instrumentors. This supports enriching metrics with context-specific information available only after HTTP requests are received, at their origin rather than requiring downstream processing or additional metric calculations.
1820
1921
This was inspired by OpenTelemetry Go's net/http instrumentation Labeler
2022
https://github.com/open-telemetry/opentelemetry-go-contrib/pull/306
23+
24+
Usage
25+
-----
26+
27+
The labeler works within the context of an instrumented request or operation. Use ``get_labeler()`` to obtain a labeler instance for the current context, then add attributes using the ``add()`` or ``add_attributes()`` methods.
28+
29+
Example with Flask
30+
------------------
31+
32+
Here's an example showing how to use the labeler with Flask instrumentation:
33+
34+
.. code-block:: python
35+
36+
from flask import Flask
37+
from opentelemetry.instrumentation._labeler import get_labeler
38+
from opentelemetry.instrumentation.flask import FlaskInstrumentor
39+
40+
app = Flask(__name__)
41+
FlaskInstrumentor().instrument_app(app)
42+
43+
@app.route("/healthcheck")
44+
def healthcheck():
45+
# Get the labeler for the current request
46+
labeler = get_labeler()
47+
48+
labeler.add_attributes(
49+
{
50+
"endpoint_type": "healthcheck",
51+
"internal_request": True,
52+
}
53+
)
54+
return "OK"
55+
56+
@app.route("/user/<user_id>")
57+
def user_profile(user_id):
58+
labeler = get_labeler()
59+
60+
# Can add individual attributes or multiple at once
61+
labeler.add("user_id", user_id)
62+
labeler.add_attributes(
63+
{
64+
"has_premium": user_id in ["123", "456"],
65+
"experiment_group": "control",
66+
"feature_enabled": True,
67+
"user_segment": "active",
68+
}
69+
)
70+
71+
return f"Got user profile for {user_id}"
72+
73+
The labeler also works with auto-instrumentation and those instrumentors that have implemented custom attributes support for metrics.
2174
"""
2275

2376
from opentelemetry.instrumentation._labeler._internal import (

opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/_internal/__init__.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@
2424

2525
class Labeler:
2626
"""
27-
Labeler can be used by instrumented code or distro to add custom attributes
28-
to the metrics recorded by those OpenTelemetry instrumentations reading it.
29-
30-
Labeler accumulates custom attributes for OpenTelemetry metrics for the
31-
current request in context.
27+
Stores custom attributes for the current request in context.
3228
3329
This feature is experimental and unstable.
3430
"""
@@ -142,13 +138,11 @@ def enhance_metric_attributes(
142138
max_attr_value_length: int = 100,
143139
) -> Dict[str, Any]:
144140
"""
145-
This function combines base_attributes with custom attributes
146-
from the current labeler.
147-
148-
Custom attributes are skipped if they would override base_attributes,
149-
exceed max_custom_attrs number, or are not simple types (str, int, float,
150-
bool). If custom attributes have string values exceeding the
151-
max_attr_value_length, then they are truncated.
141+
Combines base_attributes with custom attributes from the current labeler,
142+
returning a new dictionary of attributes. Custom attributes are skipped
143+
if they would override base_attributes, exceed max_custom_attrs number,
144+
or are not simple types (str, int, float, bool). If custom attributes
145+
have string values exceeding the max_attr_value_length, then they are truncated.
152146
153147
Args:
154148
base_attributes: The base attributes for the metric

opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/example.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

opentelemetry-instrumentation/tests/test_labeler.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ def test_thread_safety(self):
8282
num_operations = 100
8383

8484
def worker(thread_id):
85-
for i in range(num_operations):
86-
labeler.add(f"thread_{thread_id}_key_{i}", f"value_{i}")
85+
for i_operation in range(num_operations):
86+
labeler.add(
87+
f"thread_{thread_id}_key_{i_operation}",
88+
f"value_{i_operation}",
89+
)
8790

8891
# Start multiple threads
8992
threads = []
@@ -158,11 +161,14 @@ def context_worker(context_id, results):
158161
results = {}
159162

160163
# Run in different contextvars contexts
161-
for i in range(3):
164+
for i_operation in range(3):
162165
ctx = contextvars.copy_context()
163-
ctx.run(context_worker, i, results)
166+
ctx.run(context_worker, i_operation, results)
164167

165168
# Each context should have its own labeler with its own values
166-
for i in range(3):
167-
expected = {"context_id": i, "value": f"context_{i}"}
168-
self.assertEqual(results[i], expected)
169+
for i_operation in range(3):
170+
expected = {
171+
"context_id": i_operation,
172+
"value": f"context_{i_operation}",
173+
}
174+
self.assertEqual(results[i_operation], expected)

0 commit comments

Comments
 (0)