diff --git a/scripts/ci/ci_trace_report.py b/scripts/ci/ci_trace_report.py index 42ce553c8..bbfe4a932 100755 --- a/scripts/ci/ci_trace_report.py +++ b/scripts/ci/ci_trace_report.py @@ -33,7 +33,6 @@ import argparse import urllib.request import urllib.error - # ========== Default Configuration ========== DEFAULT_ENDPOINT = "https://proj-xtrace-495e81719a1fd9a2c5fd671eefafbe-cn-hangzhou.cn-hangzhou.log.aliyuncs.com/apm/trace/opentelemetry/v1/traces" DEFAULT_PROJECT = "proj-xtrace-495e81719a1fd9a2c5fd671eefafbe-cn-hangzhou" @@ -42,6 +41,7 @@ DEFAULT_WORKSPACE = "agentloop-13b8d6efb7fde6e9b193eb982ade68e2" # ========== OTLP Protobuf Manual Encoding ========== + def _encode_varint(value): result = bytearray() while value > 0x7F: @@ -69,7 +69,11 @@ def _encode_int_field(field_number, value): def _encode_message_field(field_number, message_bytes): - return _encode_tag(field_number, 2) + _encode_varint(len(message_bytes)) + message_bytes + return ( + _encode_tag(field_number, 2) + + _encode_varint(len(message_bytes)) + + message_bytes + ) def _encode_key_value(key, value_str): @@ -84,9 +88,18 @@ def _encode_status(status_code, status_msg=""): return data -def _encode_span(trace_id_bytes, span_id_bytes, parent_span_id_bytes, - name, start_time_unix_nano, end_time_unix_nano, - span_kind, attributes, status_code, status_msg=""): +def _encode_span( + trace_id_bytes, + span_id_bytes, + parent_span_id_bytes, + name, + start_time_unix_nano, + end_time_unix_nano, + span_kind, + attributes, + status_code, + status_msg="", +): data = b"" data += _encode_bytes_field(1, trace_id_bytes) data += _encode_bytes_field(2, span_id_bytes) @@ -129,6 +142,7 @@ def _encode_traces_data(resource_spans_bytes_list): # ========== Helper Functions ========== + def _gen_trace_id(): return uuid.uuid4().bytes @@ -190,6 +204,7 @@ def _get_ci_attributes(): # ========== Trace Building & Reporting ========== + def build_trace(service_name, trace_name, status, duration_ms, attributes=None): """Build an OTLP trace payload (protobuf bytes). No external dependencies.""" trace_id = _gen_trace_id() @@ -224,9 +239,17 @@ def build_trace(service_name, trace_name, status, duration_ms, attributes=None): return _encode_traces_data([resource_spans]) -def report_ci_trace(service_name, trace_name, status="ok", duration_ms=1000, - endpoint=None, license_key=None, project=None, workspace=None, - extra_attributes=None): +def report_ci_trace( + service_name, + trace_name, + status="ok", + duration_ms=1000, + endpoint=None, + license_key=None, + project=None, + workspace=None, + extra_attributes=None, +): """ Report CI Trace data. Returns (success: bool, message: str). Never raises exceptions; returns False on failure. @@ -259,7 +282,9 @@ def report_ci_trace(service_name, trace_name, status="ok", duration_ms=1000, "x-cms-workspace": workspace, } - req = urllib.request.Request(endpoint, data=payload, headers=headers, method="POST") + req = urllib.request.Request( + endpoint, data=payload, headers=headers, method="POST" + ) try: with urllib.request.urlopen(req, timeout=10) as resp: status_code = resp.status @@ -274,31 +299,45 @@ def report_ci_trace(service_name, trace_name, status="ok", duration_ms=1000, f"({status}, {duration_ms}ms)" ) else: - return False, ( - f"[Trace] failed: HTTP {status_code} - {resp_body[:200]}" - ) + return False, (f"[Trace] failed: HTTP {status_code} - {resp_body[:200]}") except Exception as e: return False, f"[Trace] error: {type(e).__name__}: {str(e)}" def main(): parser = argparse.ArgumentParser(description="CI AgentLoop Trace Reporter") - parser.add_argument("--service", dest="service_name", - default=os.getenv("TRACE_SERVICE", ""), - help="Service name (also via TRACE_SERVICE env)") - parser.add_argument("--name", dest="trace_name", - default=os.getenv("TRACE_NAME", ""), - help="Trace name (also via TRACE_NAME env)") - parser.add_argument("--status", default=os.getenv("TRACE_STATUS", "ok"), - choices=["ok", "error", "running"], - help="Status: ok / error / running (default ok)") - parser.add_argument("--start-time", dest="start_time", - default=os.getenv("TRACE_START_TIME", ""), - help="Start timestamp (seconds) for duration calculation") - parser.add_argument("--duration-ms", dest="duration_ms", type=int, default=0, - help="Direct duration in ms; takes precedence over --start-time") - parser.add_argument("--attrs", default="", - help="Extra attributes (JSON string)") + parser.add_argument( + "--service", + dest="service_name", + default=os.getenv("TRACE_SERVICE", ""), + help="Service name (also via TRACE_SERVICE env)", + ) + parser.add_argument( + "--name", + dest="trace_name", + default=os.getenv("TRACE_NAME", ""), + help="Trace name (also via TRACE_NAME env)", + ) + parser.add_argument( + "--status", + default=os.getenv("TRACE_STATUS", "ok"), + choices=["ok", "error", "running"], + help="Status: ok / error / running (default ok)", + ) + parser.add_argument( + "--start-time", + dest="start_time", + default=os.getenv("TRACE_START_TIME", ""), + help="Start timestamp (seconds) for duration calculation", + ) + parser.add_argument( + "--duration-ms", + dest="duration_ms", + type=int, + default=0, + help="Direct duration in ms; takes precedence over --start-time", + ) + parser.add_argument("--attrs", default="", help="Extra attributes (JSON string)") args = parser.parse_args()