11import contextvars
22import json
33import logging
4- import os
54import typing
6- import uuid
75from _contextvars import ContextVar
86from collections .abc import Generator
97from contextlib import contextmanager
1412
1513from galileo .config import GalileoPythonConfig
1614from galileo .decorator import _experiment_id_context , _log_stream_context , _project_context , _session_id_context
15+ from galileo .utils .env_helpers import _get_log_stream_or_default , _get_project_or_default
1716from galileo .utils .retrievers import document_adapter
1817from galileo_core .schemas .logging .span import RetrieverSpan , ToolSpan , WorkflowSpan
1918from galileo_core .schemas .logging .span import Span as GalileoSpan
@@ -128,29 +127,12 @@ def __init__(self, project: Optional[str] = None, logstream: Optional[str] = Non
128127 if not api_key :
129128 raise ValueError ("API key is required." )
130129
131- if project is not None :
132- _project_context .set (project )
133- if logstream is not None :
134- _log_stream_context .set (logstream )
135-
136- # Resolve project and logstream from parameters, context, or environment variables
137- # Check context first, then environment, then generate/use defaults
138- ctx_project = _project_context .get (None )
139- ctx_logstream = _log_stream_context .get (None )
140-
141- if ctx_project is not None :
142- self .project = ctx_project
143- elif "GALILEO_PROJECT" in os .environ :
144- self .project = os .environ ["GALILEO_PROJECT" ]
145- else :
146- self .project = f"project_{ uuid .uuid4 ()} "
147-
148- if ctx_logstream is not None :
149- self .logstream = ctx_logstream
150- elif "GALILEO_LOG_STREAM" in os .environ :
151- self .logstream = os .environ ["GALILEO_LOG_STREAM" ]
152- else :
153- self .logstream = "default"
130+ # Resolve project and logstream: param first, then context var, then env var with default fallback
131+ ctx_project = project if project is not None else _project_context .get (None )
132+ ctx_logstream = logstream if logstream is not None else _log_stream_context .get (None )
133+
134+ self .project = _get_project_or_default (ctx_project )
135+ self .logstream = _get_log_stream_or_default (ctx_logstream )
154136
155137 exporter_headers = {"Galileo-API-Key" : api_key , "project" : self .project , "logstream" : self .logstream }
156138
@@ -240,13 +222,13 @@ def __init__(
240222 "OpenTelemetry packages are not installed. "
241223 "Install optional OpenTelemetry dependencies with: pip install galileo[otel]"
242224 )
243- if project is not None :
244- _project_context .set (project )
245- if logstream is not None :
246- _log_stream_context .set (logstream )
247225
248- self ._project = _project_context .get ()
249- self ._logstream = _log_stream_context .get ()
226+ # Resolve project and logstream: param first, then context var, then env var with default fallback
227+ ctx_project = project if project is not None else _project_context .get (None )
228+ ctx_logstream = logstream if logstream is not None else _log_stream_context .get (None )
229+
230+ self ._project = _get_project_or_default (ctx_project )
231+ self ._logstream = _get_log_stream_or_default (ctx_logstream )
250232
251233 # Create the exporter using the config-based approach
252234 self ._exporter = GalileoOTLPExporter (** kwargs )
@@ -259,8 +241,9 @@ def __init__(
259241 def on_start (self , span : Span , parent_context : Optional [context .Context ] = None ) -> None :
260242 """Handle span start events by delegating to the underlying processor."""
261243 # Set Galileo context attributes on the span
262- project = _project_context .get (self ._project )
263- log_stream = _log_stream_context .get (self ._logstream )
244+ # Use context var if set and not None, otherwise fall back to instance defaults
245+ project = _project_context .get (None ) or self ._project
246+ log_stream = _log_stream_context .get (None ) or self ._logstream
264247 experiment_id = _experiment_id_context .get (None )
265248 session_id = _session_id_context .get (None )
266249
0 commit comments