Skip to content

Commit fa6bbe6

Browse files
committed
chore: replace opencensus with opentelemetry
1 parent 86663c6 commit fa6bbe6

File tree

5 files changed

+104
-117
lines changed

5 files changed

+104
-117
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-slim>=0.111.0",
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",

pccommon/requirements.txt

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,27 @@ azure-core==1.30.2
1414
# via
1515
# azure-data-tables
1616
# azure-identity
17+
# azure-monitor-opentelemetry-exporter
1718
# azure-storage-blob
18-
# opencensus-ext-azure
19+
# msrest
1920
azure-data-tables==12.5.0
2021
# via pccommon (pccommon/pyproject.toml)
21-
azure-identity==1.16.1
22+
azure-identity==1.17.1
2223
# via
23-
# opencensus-ext-azure
24+
# azure-monitor-opentelemetry-exporter
2425
# pccommon (pccommon/pyproject.toml)
26+
azure-monitor-opentelemetry-exporter==1.0.0b38
27+
# via pccommon (pccommon/pyproject.toml)
2528
azure-storage-blob==12.20.0
2629
# via pccommon (pccommon/pyproject.toml)
2730
beautifulsoup4==4.12.3
2831
# via html-sanitizer
2932
cachetools==5.3.3
30-
# via
31-
# google-auth
32-
# pccommon (pccommon/pyproject.toml)
33+
# via pccommon (pccommon/pyproject.toml)
3334
certifi==2024.7.4
34-
# via requests
35+
# via
36+
# msrest
37+
# requests
3538
cffi==1.16.0
3639
# via cryptography
3740
charset-normalizer==3.3.2
@@ -46,12 +49,8 @@ exceptiongroup==1.3.0
4649
# via anyio
4750
fastapi-slim==0.111.0
4851
# via pccommon (pccommon/pyproject.toml)
49-
google-api-core==2.19.0
50-
# via opencensus
51-
google-auth==2.30.0
52-
# via google-api-core
53-
googleapis-common-protos==1.63.1
54-
# via google-api-core
52+
fixedint==0.1.6
53+
# via azure-monitor-opentelemetry-exporter
5554
html-sanitizer==2.4.4
5655
# via pccommon (pccommon/pyproject.toml)
5756
idna==3.7
@@ -60,10 +59,13 @@ idna==3.7
6059
# pccommon (pccommon/pyproject.toml)
6160
# requests
6261
# yarl
62+
importlib-metadata==8.7.0
63+
# via opentelemetry-api
6364
isodate==0.6.1
6465
# via
6566
# azure-data-tables
6667
# azure-storage-blob
68+
# msrest
6769
lxml==5.2.2
6870
# via
6971
# html-sanitizer
@@ -78,39 +80,32 @@ msal==1.28.1
7880
# msal-extensions
7981
msal-extensions==1.1.0
8082
# via azure-identity
83+
msrest==0.7.1
84+
# via azure-monitor-opentelemetry-exporter
8185
multidict==6.0.5
8286
# via yarl
83-
opencensus==0.11.4
87+
oauthlib==3.3.1
88+
# via requests-oauthlib
89+
opentelemetry-api==1.34.1
8490
# via
85-
# opencensus-ext-azure
86-
# opencensus-ext-logging
87-
opencensus-context==0.1.3
88-
# via opencensus
89-
opencensus-ext-azure==1.1.13
90-
# via pccommon (pccommon/pyproject.toml)
91-
opencensus-ext-logging==0.1.1
92-
# via pccommon (pccommon/pyproject.toml)
91+
# azure-monitor-opentelemetry-exporter
92+
# opentelemetry-sdk
93+
# opentelemetry-semantic-conventions
94+
# pccommon (pccommon/pyproject.toml)
95+
opentelemetry-sdk==1.34.1
96+
# via
97+
# azure-monitor-opentelemetry-exporter
98+
# pccommon (pccommon/pyproject.toml)
99+
opentelemetry-semantic-conventions==0.55b1
100+
# via opentelemetry-sdk
93101
orjson==3.10.5
94102
# via pccommon (pccommon/pyproject.toml)
95103
packaging==24.1
96104
# via msal-extensions
97105
portalocker==2.8.2
98106
# via msal-extensions
99-
proto-plus==1.23.0
100-
# via google-api-core
101-
protobuf==4.25.3
102-
# via
103-
# google-api-core
104-
# googleapis-common-protos
105-
# proto-plus
106107
psutil==5.9.8
107-
# via opencensus-ext-azure
108-
pyasn1==0.6.0
109-
# via
110-
# pyasn1-modules
111-
# rsa
112-
pyasn1-modules==0.4.0
113-
# via google-auth
108+
# via azure-monitor-opentelemetry-exporter
114109
pycparser==2.22
115110
# via cffi
116111
pydantic==2.7.4
@@ -133,17 +128,16 @@ redis==4.6.0
133128
requests==2.32.3
134129
# via
135130
# azure-core
136-
# google-api-core
137131
# msal
138-
# opencensus-ext-azure
132+
# msrest
139133
# pccommon (pccommon/pyproject.toml)
140-
rsa==4.9
141-
# via google-auth
134+
# requests-oauthlib
135+
requests-oauthlib==2.0.0
136+
# via msrest
142137
six==1.16.0
143138
# via
144139
# azure-core
145140
# isodate
146-
# opencensus
147141
sniffio==1.3.1
148142
# via anyio
149143
soupsieve==2.5
@@ -159,9 +153,13 @@ typing-extensions==4.12.2
159153
# anyio
160154
# azure-core
161155
# azure-data-tables
156+
# azure-identity
162157
# azure-storage-blob
163158
# exceptiongroup
164159
# fastapi-slim
160+
# opentelemetry-api
161+
# opentelemetry-sdk
162+
# opentelemetry-semantic-conventions
165163
# pydantic
166164
# pydantic-core
167165
# starlette
@@ -171,3 +169,5 @@ urllib3==2.2.2
171169
# requests
172170
yarl==1.9.4
173171
# via azure-data-tables
172+
zipp==3.23.0
173+
# via importlib-metadata

0 commit comments

Comments
 (0)