Skip to content

Commit 2b669a2

Browse files
committed
Allow protocol selection
1 parent dab4c93 commit 2b669a2

3 files changed

Lines changed: 88 additions & 8 deletions

File tree

build.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ def run_pyinstaller(name: str, icon: str):
106106
'--hidden-import=opentelemetry.sdk.metrics.export',
107107
'--hidden-import=opentelemetry.exporter.otlp.proto.grpc.trace_exporter',
108108
'--hidden-import=opentelemetry.exporter.otlp.proto.grpc.metric_exporter',
109+
'--hidden-import=opentelemetry.exporter.otlp.proto.http.trace_exporter',
110+
'--hidden-import=opentelemetry.exporter.otlp.proto.http.metric_exporter',
109111
'--hidden-import=opentelemetry.propagate',
110112
'--collect-submodules=opentelemetry',
111113
'--collect-all=grpc',

telemetry.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@
3434
_duration_histogram = None
3535

3636
DEFAULT_OTLP_ENDPOINT = "https://grpc.public.prd.shared.perforce.com"
37+
DEFAULT_OTLP_PROTOCOL = "grpc"
38+
39+
40+
def _get_otlp_protocol() -> str:
41+
return os.getenv("OTEL_EXPORTER_OTLP_PROTOCOL", DEFAULT_OTLP_PROTOCOL)
42+
43+
44+
def _create_trace_exporter():
45+
if _get_otlp_protocol() == "grpc":
46+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
47+
else:
48+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
49+
return OTLPSpanExporter()
50+
51+
52+
def _create_metric_exporter():
53+
if _get_otlp_protocol() == "grpc":
54+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
55+
else:
56+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
57+
return OTLPMetricExporter()
3758

3859

3960
def init_telemetry(service_name: str, service_version: str) -> None:
@@ -56,15 +77,14 @@ def init_telemetry(service_name: str, service_version: str) -> None:
5677
})
5778
provider = TracerProvider(resource=resource)
5879

59-
# Default the export destination to the Perforce gRPC collector. Users
60-
# override only the endpoint via OTEL_EXPORTER_OTLP_ENDPOINT;
61-
# OTEL_SDK_DISABLED=true turns tracing off entirely.
80+
# Default export destination/protocol for shipped releases (gRPC + Perforce
81+
# collector). PAG or local dev may override via OTEL_EXPORTER_OTLP_ENDPOINT
82+
# and OTEL_EXPORTER_OTLP_PROTOCOL; OTEL_SDK_DISABLED=true disables telemetry.
6283
if not os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"):
6384
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = DEFAULT_OTLP_ENDPOINT
6485

6586
try:
66-
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
67-
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
87+
provider.add_span_processor(BatchSpanProcessor(_create_trace_exporter()))
6888
except Exception:
6989
logger.debug("OTLP trace exporter setup failed", exc_info=True)
7090

@@ -77,8 +97,7 @@ def init_telemetry(service_name: str, service_version: str) -> None:
7797

7898
readers = []
7999
try:
80-
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
81-
readers.append(PeriodicExportingMetricReader(OTLPMetricExporter()))
100+
readers.append(PeriodicExportingMetricReader(_create_metric_exporter()))
82101
except Exception:
83102
logger.debug("OTLP metric exporter setup failed", exc_info=True)
84103

tests/test_telemetry.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@
2121
import pytest
2222

2323
from models.result import BaseResult
24-
from telemetry import DEFAULT_OTLP_ENDPOINT, _record_metrics, init_telemetry, run_tool
24+
from telemetry import (
25+
DEFAULT_OTLP_ENDPOINT,
26+
DEFAULT_OTLP_PROTOCOL,
27+
_create_metric_exporter,
28+
_create_trace_exporter,
29+
_get_otlp_protocol,
30+
_record_metrics,
31+
init_telemetry,
32+
run_tool,
33+
)
2534

2635

2736
def _make_ctx(meta=None):
@@ -232,3 +241,53 @@ def test_explicit_endpoint_not_overridden(self, monkeypatch):
232241
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
233242
init_telemetry("perfecto-mcp", "1.0.0")
234243
assert os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] == "http://localhost:4317"
244+
245+
def test_defaults_protocol_to_grpc(self, monkeypatch):
246+
monkeypatch.delenv("OTEL_EXPORTER_OTLP_PROTOCOL", raising=False)
247+
assert _get_otlp_protocol() == DEFAULT_OTLP_PROTOCOL
248+
assert DEFAULT_OTLP_PROTOCOL == "grpc"
249+
250+
def test_http_protocol_env(self, monkeypatch):
251+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf")
252+
assert _get_otlp_protocol() == "http/protobuf"
253+
254+
def test_does_not_raise_with_http_protocol(self, monkeypatch):
255+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf")
256+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")
257+
init_telemetry("perfecto-mcp", "1.0.0")
258+
259+
def test_grpc_trace_exporter_selected(self, monkeypatch):
260+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc")
261+
with patch(
262+
"opentelemetry.exporter.otlp.proto.grpc.trace_exporter.OTLPSpanExporter",
263+
return_value=MagicMock(),
264+
) as grpc_exporter:
265+
_create_trace_exporter()
266+
grpc_exporter.assert_called_once()
267+
268+
def test_http_trace_exporter_selected(self, monkeypatch):
269+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf")
270+
with patch(
271+
"opentelemetry.exporter.otlp.proto.http.trace_exporter.OTLPSpanExporter",
272+
return_value=MagicMock(),
273+
) as http_exporter:
274+
_create_trace_exporter()
275+
http_exporter.assert_called_once()
276+
277+
def test_grpc_metric_exporter_selected(self, monkeypatch):
278+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc")
279+
with patch(
280+
"opentelemetry.exporter.otlp.proto.grpc.metric_exporter.OTLPMetricExporter",
281+
return_value=MagicMock(),
282+
) as grpc_exporter:
283+
_create_metric_exporter()
284+
grpc_exporter.assert_called_once()
285+
286+
def test_http_metric_exporter_selected(self, monkeypatch):
287+
monkeypatch.setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/json")
288+
with patch(
289+
"opentelemetry.exporter.otlp.proto.http.metric_exporter.OTLPMetricExporter",
290+
return_value=MagicMock(),
291+
) as http_exporter:
292+
_create_metric_exporter()
293+
http_exporter.assert_called_once()

0 commit comments

Comments
 (0)