Skip to content

Commit f3a4ff8

Browse files
committed
feat(memorystore): migrate Redis client-side metrics sample to OTLP
1 parent 61ffefd commit f3a4ff8

3 files changed

Lines changed: 78 additions & 31 deletions

File tree

‎memorystore/redis/client_side_metrics/main.py‎

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,74 @@
1616
import os
1717
import time
1818

19+
import google.auth
20+
from google.auth.transport.grpc import AuthMetadataPlugin
21+
import google.auth.transport.requests
22+
import grpc
1923
from opentelemetry import metrics, trace
20-
from opentelemetry.exporter.cloud_monitoring import (
21-
CloudMonitoringMetricsExporter,
24+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
25+
OTLPMetricExporter,
26+
)
27+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
28+
OTLPSpanExporter,
2229
)
23-
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
2430
from opentelemetry.instrumentation.redis import RedisInstrumentor
31+
from opentelemetry.resourcedetector.gcp_resource_detector import (
32+
GoogleCloudResourceDetector,
33+
)
2534
from opentelemetry.sdk.metrics import MeterProvider
2635
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
36+
from opentelemetry.sdk.resources import Resource, get_aggregated_resources
2737
from opentelemetry.sdk.trace import TracerProvider
2838
from opentelemetry.sdk.trace.export import BatchSpanProcessor
2939
import redis
3040
from redis.exceptions import ConnectionError, TimeoutError
3141

3242

43+
def init_telemetry():
44+
"""Initializes OpenTelemetry with OTLP Exporters and returns the SDK objects."""
45+
credentials, project_id = google.auth.default(
46+
scopes=["https://www.googleapis.com/auth/cloud-platform"]
47+
)
48+
request = google.auth.transport.requests.Request()
49+
auth_metadata_plugin = AuthMetadataPlugin(
50+
credentials=credentials, request=request
51+
)
52+
channel_creds = grpc.composite_channel_credentials(
53+
grpc.ssl_channel_credentials(),
54+
grpc.metadata_call_credentials(auth_metadata_plugin),
55+
)
3356

57+
resource = get_aggregated_resources([GoogleCloudResourceDetector()])
58+
if project_id:
59+
resource = resource.merge(
60+
Resource.create({"gcp.project_id": project_id})
61+
)
3462

35-
def init_telemetry():
36-
"""Initializes OpenTelemetry with GCP Exporters and returns the SDK objects."""
3763
# 1. Initialize Tracing
38-
tracer_provider = TracerProvider()
64+
tracer_provider = TracerProvider(resource=resource)
3965
tracer_provider.add_span_processor(
40-
BatchSpanProcessor(CloudTraceSpanExporter())
66+
BatchSpanProcessor(
67+
OTLPSpanExporter(
68+
endpoint="telemetry.googleapis.com:443",
69+
credentials=channel_creds,
70+
)
71+
)
4172
)
4273
trace.set_tracer_provider(tracer_provider)
4374
tracer = trace.get_tracer("redis.client")
4475

4576
# 2. Initialize Metrics
46-
metrics_exporter = CloudMonitoringMetricsExporter()
77+
metrics_exporter = OTLPMetricExporter(
78+
endpoint="telemetry.googleapis.com:443",
79+
credentials=channel_creds,
80+
)
4781
metric_reader = PeriodicExportingMetricReader(
4882
metrics_exporter, export_interval_millis=10000
4983
)
50-
meter_provider = MeterProvider(metric_readers=[metric_reader])
84+
meter_provider = MeterProvider(
85+
resource=resource, metric_readers=[metric_reader]
86+
)
5187
metrics.set_meter_provider(meter_provider)
5288
meter = metrics.get_meter("redis.metrics")
5389

@@ -143,6 +179,7 @@ def smart_redis_call(
143179
raise e
144180
time.sleep((2**attempt) * 0.1)
145181

182+
146183
if __name__ == "__main__":
147184
tracer, redis_metrics, tracer_provider, meter_provider = init_telemetry()
148185
redis_pool, redis_client = init_redis_pool()
@@ -171,6 +208,6 @@ def smart_redis_call(
171208
except Exception as e:
172209
print(f"Error: {e}")
173210

174-
tracer_provider.force_flush()
175-
meter_provider.force_flush()
211+
tracer_provider.shutdown()
212+
meter_provider.shutdown()
176213
# [END memorystore_redis_client_side_metrics]

‎memorystore/redis/client_side_metrics/main_test.py‎

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
from unittest import mock
1616

1717
import main
18+
from opentelemetry.sdk.metrics import MeterProvider
19+
from opentelemetry.sdk.trace import TracerProvider
1820
import pytest
21+
import redis
1922
from redis.exceptions import ConnectionError
2023

2124

@@ -135,7 +138,7 @@ def test_smart_redis_call_permanent_failure():
135138

136139

137140
def test_init_redis_pool_live(monkeypatch):
138-
"""Verifies init_redis_pool correctly parses environment variables without network calls."""
141+
"""Verifies init_redis_pool correctly parses env vars without network calls."""
139142
monkeypatch.setenv("REDISHOST", "10.0.0.1")
140143
monkeypatch.setenv("REDISPORT", "7000")
141144

@@ -156,20 +159,14 @@ def test_init_redis_pool_live(monkeypatch):
156159

157160

158161
def test_smart_redis_call_live_or_skip():
159-
"""Integration Test: Hits a real Redis endpoint if running locally at localhost:6379."""
160-
import main as live_main
161-
from opentelemetry.sdk.metrics import MeterProvider
162-
from opentelemetry.sdk.trace import TracerProvider
163-
import pytest
164-
import redis
165-
162+
"""Integration Test: Hits real Redis endpoint if running at localhost:6379."""
166163
# Initialize REAL No-op OpenTelemetry SDK providers (invoked directly)
167164
TracerProvider()
168165
mp = MeterProvider()
169166

170167
try:
171168
# Exercise actual pool creation and connectivity ping
172-
redis_pool, redis_client = live_main.init_redis_pool()
169+
redis_pool, redis_client = main.init_redis_pool()
173170
redis_client.ping()
174171
except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError):
175172
pytest.skip(
@@ -188,7 +185,7 @@ def test_smart_redis_call_live_or_skip():
188185

189186
try:
190187
# Run a real Redis write hitting the ACTUAL endpoint (invoked directly)
191-
live_main.smart_redis_call(
188+
main.smart_redis_call(
192189
"set_test",
193190
redis_client.set,
194191
redis_pool,
@@ -197,7 +194,7 @@ def test_smart_redis_call_live_or_skip():
197194
"live_val",
198195
)
199196

200-
result_get = live_main.smart_redis_call(
197+
result_get = main.smart_redis_call(
201198
"get_test",
202199
redis_client.get,
203200
redis_pool,
@@ -214,17 +211,24 @@ def test_smart_redis_call_live_or_skip():
214211
redis_pool.disconnect()
215212

216213

214+
@mock.patch(
215+
"main.google.auth.default",
216+
return_value=(mock.MagicMock(), "test-project"),
217+
)
218+
@mock.patch("main.GoogleCloudResourceDetector")
217219
@mock.patch("main.BatchSpanProcessor")
218220
@mock.patch("main.PeriodicExportingMetricReader")
219-
@mock.patch("main.CloudTraceSpanExporter")
220-
@mock.patch("main.CloudMonitoringMetricsExporter")
221+
@mock.patch("main.OTLPSpanExporter")
222+
@mock.patch("main.OTLPMetricExporter")
221223
@mock.patch("main.RedisInstrumentor")
222224
def test_init_telemetry_mocks(
223225
mock_redis_instrumentor,
224-
mock_cloud_metrics,
225-
mock_cloud_trace,
226+
mock_otlp_metrics,
227+
mock_otlp_trace,
226228
mock_metric_reader,
227229
mock_span_processor,
230+
mock_gcp_detector,
231+
mock_google_auth,
228232
):
229233
"""Verifies the init_telemetry function correctly instruments Redis."""
230234
tracer, redis_metrics, tp, mp = main.init_telemetry()
@@ -238,6 +242,9 @@ def test_init_telemetry_mocks(
238242
assert "client_block_hist" in redis_metrics
239243

240244
mock_redis_instrumentor.return_value.instrument.assert_called_once()
241-
mock_cloud_trace.assert_called_once()
242-
mock_cloud_metrics.assert_called_once()
243-
245+
mock_otlp_trace.assert_called_once()
246+
mock_otlp_metrics.assert_called_once()
247+
_, kwargs_trace = mock_otlp_trace.call_args
248+
assert kwargs_trace.get("endpoint") == "telemetry.googleapis.com:443"
249+
_, kwargs_metrics = mock_otlp_metrics.call_args
250+
assert kwargs_metrics.get("endpoint") == "telemetry.googleapis.com:443"

‎memorystore/redis/client_side_metrics/requirements.txt‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ redis==7.0.1
22
opentelemetry-api==1.39.1
33
opentelemetry-sdk==1.39.1
44
opentelemetry-instrumentation-redis==0.60b1
5-
opentelemetry-exporter-gcp-trace==1.11.0
6-
opentelemetry-exporter-gcp-monitoring==1.11.0a0
5+
opentelemetry-exporter-otlp-proto-grpc==1.39.1
6+
opentelemetry-resourcedetector-gcp==1.11.0a0
7+
google-auth==2.38.0
8+
grpcio==1.70.0
9+
requests==2.32.3

0 commit comments

Comments
 (0)