3535# Config
3636# ---------------------------------------------------------------------------
3737
38- WORKSPACE = os .environ ["OPIK_WORKSPACE" ]
39- OPIK_BASE_URL = os .environ .get ("OPIK_URL_OVERRIDE" , "https://www.comet.com/opik/api" )
40- GOVERNANCE_TAG = "governance" # must match the tag used in agent_tracing.py
38+ WORKSPACE = os .environ .get ("OPIK_WORKSPACE" )
39+ OPIK_BASE_URL = os .environ .get ("OPIK_URL_OVERRIDE" , "https://www.comet.com/opik/api" )
40+ GOVERNANCE_TAG = "governance" # must match the tag used in agent_tracing.py
41+
42+ # No Opik credentials -> describe the extraction and exit without calling the Opik API.
43+ DRY_RUN = not (os .environ .get ("OPIK_API_KEY" ) and WORKSPACE )
4144
4245_now = datetime .now (UTC )
4346
4447# Metric types to extract. Each maps to one get_project_metrics() call.
4548# See the full list of available values in the SDK docs linked above.
4649METRIC_TYPES = [
47- "FEEDBACK_SCORES" , # average per named feedback score
50+ "FEEDBACK_SCORES" , # average per named feedback score
4851]
4952
5053# Interval for aggregation. Choose one: "HOURLY" | "DAILY" | "WEEKLY" | "TOTAL"
@@ -66,6 +69,7 @@ def build_client() -> OpikApi:
6669# Project enumeration
6770# ---------------------------------------------------------------------------
6871
72+
6973def list_all_projects (client : OpikApi ) -> list [dict ]:
7074 """Page through find_projects() and return [{"id": ..., "name": ...}, ...]."""
7175 projects = []
@@ -96,6 +100,7 @@ def list_all_projects(client: OpikApi) -> list[dict]:
96100# TraceFilterPublic(field="metadata", key="business_unit", operator="=", value="retail")
97101# ---------------------------------------------------------------------------
98102
103+
99104def _governance_filters (metadata_slice : dict [str , str ] | None = None ) -> list [TraceFilterPublic ]:
100105 """
101106 Build the filter list for a governance extraction.
@@ -105,9 +110,7 @@ def _governance_filters(metadata_slice: dict[str, str] | None = None) -> list[Tr
105110 TraceFilterPublic (field = "tags" , operator = "contains" , value = GOVERNANCE_TAG ),
106111 ]
107112 for key , value in (metadata_slice or {}).items ():
108- filters .append (
109- TraceFilterPublic (field = "metadata" , key = key , operator = "=" , value = value )
110- )
113+ filters .append (TraceFilterPublic (field = "metadata" , key = key , operator = "=" , value = value ))
111114 return filters
112115
113116
@@ -138,6 +141,7 @@ def _governance_filters(metadata_slice: dict[str, str] | None = None) -> list[Tr
138141# Metrics extraction
139142# ---------------------------------------------------------------------------
140143
144+
141145def fetch_metrics_for_project (
142146 client : OpikApi ,
143147 project_id : str ,
@@ -153,7 +157,7 @@ def fetch_metrics_for_project(
153157 result.name — score name (e.g. "composite_risk_score")
154158 result.data — list of DataPointNumberPublic (time, value) data points
155159 """
156- trace_filters = _governance_filters (metadata_slice )
160+ trace_filters = _governance_filters (metadata_slice )
157161 interval_start = _now - timedelta (days = LOOKBACK_DAYS )
158162 req_opts : RequestOptions = {"timeout_in_seconds" : 60 }
159163 metrics : dict = {}
@@ -192,15 +196,16 @@ def fetch_metrics_for_project(
192196# Main pipeline
193197# ---------------------------------------------------------------------------
194198
199+
195200def run_extraction () -> list [dict ]:
196- print (f"\n { '=' * 60 } " )
201+ print (f"\n { '=' * 60 } " )
197202 print (f"Governance Metrics Extraction { _now .strftime ('%Y-%m-%d %H:%M UTC' )} " )
198203 print (f"Workspace : { WORKSPACE } " )
199204 print (f"Tag : { GOVERNANCE_TAG } " )
200205 print (f"Interval : { INTERVAL } | Look-back: { LOOKBACK_DAYS } days" )
201- print (f"{ '=' * 60 } \n " )
206+ print (f"{ '=' * 60 } \n " )
202207
203- client = build_client ()
208+ client = build_client ()
204209 projects = list_all_projects (client )
205210 payloads = []
206211
@@ -220,11 +225,7 @@ def run_extraction() -> list[dict]:
220225 trace_filters = _governance_filters (),
221226 request_options = {"timeout_in_seconds" : 60 },
222227 )
223- probe_has_data = any (
224- point .value
225- for result in (probe .results or [])
226- for point in (result .data or [])
227- )
228+ probe_has_data = any (point .value for result in (probe .results or []) for point in (result .data or []))
228229 if not probe_has_data :
229230 print (" No governance-tagged traces — skipping.\n " )
230231 continue
@@ -239,17 +240,17 @@ def run_extraction() -> list[dict]:
239240 for label , metadata_slice in slices_to_run :
240241 sliced_metrics [label ] = {
241242 "slice_filter" : metadata_slice ,
242- "metrics" : fetch_metrics_for_project (client , project ["id" ], metadata_slice ),
243+ "metrics" : fetch_metrics_for_project (client , project ["id" ], metadata_slice ),
243244 }
244245
245246 payload = {
246- "schema_version" : "2.0" ,
247- "extracted_at" : _now .isoformat (),
248- "workspace" : WORKSPACE ,
249- "project_id" : project ["id" ],
250- "project_name" : project ["name" ],
251- "governance_tag" : GOVERNANCE_TAG ,
252- "slices" : sliced_metrics ,
247+ "schema_version" : "2.0" ,
248+ "extracted_at" : _now .isoformat (),
249+ "workspace" : WORKSPACE ,
250+ "project_id" : project ["id" ],
251+ "project_name" : project ["name" ],
252+ "governance_tag" : GOVERNANCE_TAG ,
253+ "slices" : sliced_metrics ,
253254 }
254255 payloads .append (payload )
255256
@@ -282,4 +283,11 @@ def _push_to_reporting_endpoint(payloads: list[dict]) -> None:
282283
283284
284285if __name__ == "__main__" :
286+ if DRY_RUN :
287+ print (
288+ "[DRY RUN] Opik creds not set — would extract governance metrics across "
289+ f"all projects for '{ GOVERNANCE_TAG } '-tagged traces and build the reporting payload."
290+ )
291+ raise SystemExit (0 )
292+
285293 run_extraction ()
0 commit comments