1515from __future__ import annotations
1616
1717import logging
18+ from typing import cast
19+ from typing import Optional
20+ from typing import TYPE_CHECKING
1821
1922import google .auth
2023from opentelemetry .sdk ._logs import LogRecordProcessor
2932from ..utils .feature_decorator import experimental
3033from .setup import OTelHooks
3134
35+ if TYPE_CHECKING :
36+ from google .auth .credentials import Credentials
37+
3238logger = logging .getLogger ('google_adk.' + __name__ )
3339
3440
@@ -37,34 +43,43 @@ def get_gcp_exporters(
3743 enable_cloud_tracing : bool = False ,
3844 enable_cloud_metrics : bool = False ,
3945 enable_cloud_logging : bool = False ,
46+ google_auth : Optional [tuple [Credentials , str ]] = None ,
4047) -> OTelHooks :
4148 """Returns GCP OTel exporters to be used in the app.
4249
4350 Args:
4451 enable_tracing: whether to enable tracing to Cloud Trace.
4552 enable_metrics: whether to enable raporting metrics to Cloud Monitoring.
4653 enable_logging: whether to enable sending logs to Cloud Logging.
54+ google_auth: optional custom credentials and project_id. google.auth.default() used when this is omitted.
4755 """
48- _ , project_id = google .auth .default ()
56+
57+ credentials , project_id = (
58+ google_auth if google_auth is not None else google .auth .default ()
59+ )
60+ if TYPE_CHECKING :
61+ credentials = cast (Credentials , credentials )
62+ project_id = cast (str , project_id )
63+
4964 if not project_id :
5065 logger .warning (
5166 'Cannot determine GCP Project. OTel GCP Exporters cannot be set up.'
5267 ' Please make sure to log into correct GCP Project.'
5368 )
5469 return OTelHooks ()
5570
56- span_processors = []
71+ span_processors : list [ SpanProcessor ] = []
5772 if enable_cloud_tracing :
58- exporter = _get_gcp_span_exporter (project_id )
73+ exporter = _get_gcp_span_exporter (credentials )
5974 span_processors .append (exporter )
6075
61- metric_readers = []
76+ metric_readers : list [ MetricReader ] = []
6277 if enable_cloud_metrics :
6378 exporter = _get_gcp_metrics_exporter (project_id )
6479 if exporter :
6580 metric_readers .append (exporter )
6681
67- log_record_processors = []
82+ log_record_processors : list [ LogRecordProcessor ] = []
6883 if enable_cloud_logging :
6984 exporter = _get_gcp_logs_exporter (project_id )
7085 if exporter :
@@ -77,10 +92,18 @@ def get_gcp_exporters(
7792 )
7893
7994
80- def _get_gcp_span_exporter (project_id : str ) -> SpanProcessor :
81- from opentelemetry .exporter .cloud_trace import CloudTraceSpanExporter
95+ def _get_gcp_span_exporter (credentials : Credentials ) -> SpanProcessor :
96+ """Adds OTEL span exporter to telemetry.googleapis.com"""
97+
98+ from google .auth .transport .requests import AuthorizedSession
99+ from opentelemetry .exporter .otlp .proto .http .trace_exporter import OTLPSpanExporter
82100
83- return BatchSpanProcessor (CloudTraceSpanExporter (project_id = project_id ))
101+ return BatchSpanProcessor (
102+ OTLPSpanExporter (
103+ session = AuthorizedSession (credentials = credentials ),
104+ endpoint = 'https://telemetry.googleapis.com/v1/traces' ,
105+ )
106+ )
84107
85108
86109def _get_gcp_metrics_exporter (project_id : str ) -> MetricReader :
@@ -101,15 +124,22 @@ def _get_gcp_logs_exporter(project_id: str) -> LogRecordProcessor:
101124 )
102125
103126
104- def get_gcp_resource () -> Resource :
105- # The OTELResourceDetector populates resource labels from
106- # environment variables like OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES.
107- # Then the GCP detector adds attributes corresponding to a correct
108- # monitored resource if ADK runs on one of supported platforms
109- # (e.g. GCE, GKE, CloudRun).
110-
111- resource = OTELResourceDetector ().detect ()
127+ def get_gcp_resource (project_id : Optional [str ] = None ) -> Resource :
128+ """Returns OTEL with attributes specified in the following order (attributes specified later, overwrite those specified earlier):
129+ 1. Populates gcp.project_id attribute from the project_id argument if present.
130+ 2. OTELResourceDetector populates resource labels from environment variables like OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES.
131+ 3. GCP detector adds attributes corresponding to a correct monitored resource if ADK runs on one of supported platforms (e.g. GCE, GKE, CloudRun).
112132
133+ Args:
134+ project_id: project id to fill out as `gcp.project_id` on the OTEL resource.
135+ This may be overwritten by OTELResourceDetector, if `gcp.project_id` is present in `OTEL_RESOURCE_ATTRIBUTES` env var.
136+ """
137+ resource = Resource (
138+ attributes = {'gcp.project_id' : project_id }
139+ if project_id is not None
140+ else {}
141+ )
142+ resource = resource .merge (OTELResourceDetector ().detect ())
113143 try :
114144 from opentelemetry .resourcedetector .gcp_resource_detector import GoogleCloudResourceDetector
115145
@@ -121,5 +151,4 @@ def get_gcp_resource() -> Resource:
121151 'Cloud not import opentelemetry.resourcedetector.gcp_resource_detector'
122152 ' GCE, GKE or CloudRun related resource attributes may be missing'
123153 )
124-
125154 return resource
0 commit comments