Skip to content

Commit 36b0156

Browse files
committed
chore: replace opencensus with opentelemetry
1 parent 07b79fe commit 36b0156

File tree

5 files changed

+142
-160
lines changed

5 files changed

+142
-160
lines changed

pccommon/pccommon/constants.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import os
22

3-
from opencensus.trace.attributes_helper import COMMON_ATTRIBUTES
4-
53
CACHE_KEY_ITEM = "/item"
64

75
DEFAULT_COLLECTION_CONFIG_TABLE_NAME = "collectionconfig"
@@ -30,10 +28,11 @@
3028

3129
HTTP_429_TOO_MANY_REQUESTS = 429
3230

33-
HTTP_PATH = COMMON_ATTRIBUTES["HTTP_PATH"]
34-
HTTP_URL = COMMON_ATTRIBUTES["HTTP_URL"]
35-
HTTP_STATUS_CODE = COMMON_ATTRIBUTES["HTTP_STATUS_CODE"]
36-
HTTP_METHOD = COMMON_ATTRIBUTES["HTTP_METHOD"]
31+
# TODO: switch to new stable http semantic conventions
32+
# https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/
33+
HTTP_PATH = "http.path"
34+
HTTP_URL = "http.url"
35+
HTTP_METHOD = "http.method"
3736

3837
# This is the Azurite storage account key.
3938
# This is not a key for a real Storage Account and is publicly accessible

pccommon/pccommon/logging.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
from typing import Optional, Tuple, Union, cast
88
from urllib.parse import urlparse
99

10+
from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter
1011
from fastapi import Request
11-
from opencensus.ext.azure.log_exporter import AzureLogHandler
12+
from opentelemetry._logs import set_logger_provider
13+
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
14+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
1215

1316
from pccommon.config import get_apis_config
1417
from pccommon.constants import (
@@ -104,15 +107,19 @@ def init_logging(service_name: str, app_root_path: str) -> None:
104107
if config.debug:
105108
logger.setLevel(logging.DEBUG)
106109

107-
# Azure log handler
108110
instrumentation_key = config.app_insights_instrumentation_key
109111
if instrumentation_key:
110-
azure_handler = AzureLogHandler(
112+
logger_provider = LoggerProvider()
113+
set_logger_provider(logger_provider)
114+
115+
exporter = AzureMonitorLogExporter(
111116
connection_string=f"InstrumentationKey={instrumentation_key}"
112117
)
113-
azure_handler.addFilter(CustomDimensionsFilter())
118+
logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
114119

115-
logger.addHandler(azure_handler)
120+
otel_handler = LoggingHandler(level=logging.NOTSET)
121+
otel_handler.addFilter(CustomDimensionsFilter())
122+
logger.addHandler(otel_handler)
116123
else:
117124
logger.info(f"Azure log handler not attached: {package} (missing key)")
118125

pccommon/pccommon/tracing.py

Lines changed: 43 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import json
22
import logging
33
import re
4-
from typing import List, Optional, Tuple, Union, cast
4+
from typing import Any, List, Optional, Tuple, Union, cast
55

6+
from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter
67
from fastapi import Request
7-
from opencensus.ext.azure.trace_exporter import AzureExporter
8-
from opencensus.trace import execution_context
9-
from opencensus.trace.samplers import ProbabilitySampler
10-
from opencensus.trace.span import SpanKind
11-
from opencensus.trace.tracer import Tracer
8+
from opentelemetry import trace
9+
from opentelemetry.sdk.trace import TracerProvider
10+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
11+
from opentelemetry.trace import Span, SpanKind, Tracer
1212
from starlette.datastructures import QueryParams
1313

1414
from pccommon.config import get_apis_config
@@ -26,17 +26,23 @@
2626
logger = logging.getLogger(__name__)
2727

2828

29-
exporter = (
30-
AzureExporter(
31-
connection_string=(
32-
f"InstrumentationKey={_config.app_insights_instrumentation_key}"
33-
)
29+
tracer: Optional[Tracer]
30+
31+
if _config.app_insights_instrumentation_key:
32+
tracer_provider = TracerProvider()
33+
trace.set_tracer_provider(tracer_provider)
34+
35+
azure_exporter = AzureMonitorTraceExporter(
36+
connection_string="InstrumentationKey="
37+
+ _config.app_insights_instrumentation_key
3438
)
35-
if _config.app_insights_instrumentation_key
36-
else None
37-
)
3839

39-
is_trace_enabled = exporter is not None
40+
span_processor = BatchSpanProcessor(azure_exporter)
41+
tracer_provider.add_span_processor(span_processor)
42+
43+
tracer = trace.get_tracer(__name__)
44+
else:
45+
tracer = None
4046

4147

4248
async def trace_request(
@@ -47,57 +53,29 @@ async def trace_request(
4753
request_path = request_to_path(request).strip("/")
4854

4955
if _should_trace_request(request):
50-
tracer = Tracer(
51-
exporter=exporter,
52-
sampler=ProbabilitySampler(1.0),
53-
)
54-
with tracer.span("main") as span:
56+
assert tracer
57+
with tracer.start_as_current_span("main", kind=SpanKind.SERVER) as span:
5558
(collection_id, item_id) = await _collection_item_from_request(
5659
service_name, request
5760
)
58-
span.span_kind = SpanKind.SERVER
5961

60-
# Throwing the main span into request state lets us create child spans
61-
# in downstream request processing, if there are specific things that
62-
# are slow.
6362
request.state.parent_span = span
6463

65-
# Add request dimensions to the trace prior to calling the next middleware
66-
tracer.add_attribute_to_current_span(
67-
attribute_key="ref_id",
68-
attribute_value=request.headers.get(X_AZURE_REF),
69-
)
70-
tracer.add_attribute_to_current_span(
71-
attribute_key="request_entity",
72-
attribute_value=request.headers.get(X_REQUEST_ENTITY),
73-
)
74-
tracer.add_attribute_to_current_span(
75-
attribute_key="request_ip",
76-
attribute_value=get_request_ip(request),
77-
)
78-
tracer.add_attribute_to_current_span(
79-
attribute_key=HTTP_METHOD, attribute_value=str(request.method)
80-
)
81-
tracer.add_attribute_to_current_span(
82-
attribute_key=HTTP_URL, attribute_value=str(request.url)
83-
)
84-
tracer.add_attribute_to_current_span(
85-
attribute_key=HTTP_PATH, attribute_value=request_path
86-
)
87-
tracer.add_attribute_to_current_span(
88-
attribute_key="service", attribute_value=service_name
89-
)
90-
tracer.add_attribute_to_current_span(
91-
attribute_key="in-server", attribute_value="true"
64+
span.set_attribute("ref_id", request.headers.get(X_AZURE_REF) or "")
65+
span.set_attribute(
66+
"request_entity", request.headers.get(X_REQUEST_ENTITY) or ""
9267
)
68+
span.set_attribute("request_ip", get_request_ip(request) or "")
69+
span.set_attribute(HTTP_METHOD, str(request.method))
70+
span.set_attribute(HTTP_URL, str(request.url))
71+
span.set_attribute(HTTP_PATH, request_path)
72+
span.set_attribute("service", service_name)
73+
span.set_attribute("in-server", "true")
74+
9375
if collection_id is not None:
94-
tracer.add_attribute_to_current_span(
95-
attribute_key="collection", attribute_value=collection_id
96-
)
76+
span.set_attribute("collection", collection_id)
9777
if item_id is not None:
98-
tracer.add_attribute_to_current_span(
99-
attribute_key="item", attribute_value=item_id
100-
)
78+
span.set_attribute("item", item_id)
10179

10280

10381
collection_id_re = re.compile(
@@ -139,7 +117,7 @@ def _should_trace_request(request: Request) -> bool:
139117
- Not a health check endpoint
140118
"""
141119
return (
142-
is_trace_enabled
120+
(tracer is not None)
143121
and request.method.lower() != "head"
144122
and not request.url.path.strip("/").endswith("_mgmt/ping")
145123
)
@@ -217,15 +195,17 @@ def add_stac_attributes_from_search(search_json: str, request: Request) -> None:
217195
collection_id, item_id = parse_collection_from_search(
218196
json.loads(search_json), request.method, request.query_params
219197
)
220-
parent_span = getattr(request.state, "parent_span", None)
221198

222-
current_span = execution_context.get_current_span() or parent_span
199+
current_span: Union[Optional[Any], Span]
200+
current_span = trace.get_current_span()
201+
if not current_span.is_recording():
202+
current_span = getattr(request.state, "parent_span", None)
223203

224-
if current_span:
204+
if current_span and current_span.is_recording():
225205
if collection_id is not None:
226-
current_span.add_attribute("collection", collection_id)
206+
current_span.set_attribute("collection", collection_id)
227207
if item_id is not None:
228-
current_span.add_attribute("item", item_id)
208+
current_span.set_attribute("item", item_id)
229209
else:
230210
logger.warning("No active or parent span available for adding attributes.")
231211

pccommon/pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ requires-python = ">=3.7"
1111
dependencies = [
1212
"azure-data-tables>=12.5.0",
1313
"azure-identity>=1.16.1",
14+
"azure-monitor-opentelemetry-exporter>=1.0.0b38",
1415
"azure-storage-blob>=12.20.0",
1516
"cachetools~=5.3",
1617
"fastapi==0.112.3",
1718
"html-sanitizer>=2.4.4",
1819
"idna>=3.7.0",
1920
"lxml_html_clean>=0.1.0",
20-
"opencensus-ext-azure>=1.1.13",
21-
"opencensus-ext-logging>=0.1.1",
21+
"opentelemetry-api>=1.34.1",
22+
"opentelemetry-sdk>=1.34.1",
2223
"orjson>=3.10.4",
2324
"pydantic-settings>=2.3",
2425
"pydantic>=2.7",

0 commit comments

Comments
 (0)