|
1 | 1 | // @ts-check |
2 | 2 | /// <reference types="@actions/github-script" /> |
3 | 3 |
|
4 | | -const fs = require("fs"); |
5 | 4 | const { main: exportCopilotOtelTraces } = require("./export_copilot_otel_traces.cjs"); |
6 | | - |
7 | | -const AW_INFO_PATH = "/tmp/gh-aw/aw_info.json"; |
8 | | -const AGENT_OUTPUT_PATH = "/tmp/gh-aw/agent_output.json"; |
9 | | -const gatewayEventPaths = ["/tmp/gh-aw/mcp-logs/gateway.jsonl", "/tmp/gh-aw/mcp-logs/rpc-messages.jsonl"]; |
10 | | - |
11 | | -function readJSONIfExists(path) { |
12 | | - if (!fs.existsSync(path)) { |
13 | | - return null; |
14 | | - } |
15 | | - |
16 | | - try { |
17 | | - return JSON.parse(fs.readFileSync(path, "utf8")); |
18 | | - } catch { |
19 | | - return null; |
20 | | - } |
21 | | -} |
22 | | - |
23 | | -function countBlockedRequests() { |
24 | | - let total = 0; |
25 | | - |
26 | | - for (const path of gatewayEventPaths) { |
27 | | - if (!fs.existsSync(path)) { |
28 | | - continue; |
29 | | - } |
30 | | - |
31 | | - const lines = fs.readFileSync(path, "utf8").split("\n"); |
32 | | - for (const raw of lines) { |
33 | | - const line = raw.trim(); |
34 | | - if (!line) continue; |
35 | | - try { |
36 | | - const entry = JSON.parse(line); |
37 | | - if (entry && entry.type === "DIFC_FILTERED") total++; |
38 | | - } catch { |
39 | | - // skip malformed lines |
40 | | - } |
41 | | - } |
42 | | - } |
43 | | - |
44 | | - return total; |
45 | | -} |
46 | | - |
47 | | -function uniqueCreatedItemTypes(items) { |
48 | | - const types = new Set(); |
49 | | - |
50 | | - for (const item of items) { |
51 | | - if (item && typeof item.type === "string" && item.type.trim() !== "") { |
52 | | - types.add(item.type); |
53 | | - } |
54 | | - } |
55 | | - |
56 | | - return [...types].sort(); |
57 | | -} |
58 | | - |
59 | | -function collectObservabilityData() { |
60 | | - const awInfo = readJSONIfExists(AW_INFO_PATH) || {}; |
61 | | - const agentOutput = readJSONIfExists(AGENT_OUTPUT_PATH) || { items: [], errors: [] }; |
62 | | - const items = Array.isArray(agentOutput.items) ? agentOutput.items : []; |
63 | | - const errors = Array.isArray(agentOutput.errors) ? agentOutput.errors : []; |
64 | | - // Prefer GITHUB_AW_OTEL_TRACE_ID (written to GITHUB_ENV by action_setup_otlp.cjs) |
65 | | - // so the summary always shows the trace ID that is actually present in the OTLP backend. |
66 | | - // Fall back to context.otel_trace_id for cross-workflow traces propagated from a parent. |
67 | | - // Do NOT fall back to workflow_call_id — it is not a valid OTLP trace ID. |
68 | | - const traceId = process.env.GITHUB_AW_OTEL_TRACE_ID || (awInfo.context ? awInfo.context.otel_trace_id || "" : ""); |
69 | | - |
70 | | - return { |
71 | | - workflowName: awInfo.workflow_name || "", |
72 | | - engineId: awInfo.engine_id || "", |
73 | | - traceId, |
74 | | - staged: awInfo.staged === true, |
75 | | - firewallEnabled: awInfo.firewall_enabled === true, |
76 | | - createdItemCount: items.length, |
77 | | - createdItemTypes: uniqueCreatedItemTypes(items), |
78 | | - outputErrorCount: errors.length, |
79 | | - blockedRequests: countBlockedRequests(), |
80 | | - }; |
81 | | -} |
82 | | - |
83 | | -function buildObservabilitySummary(data) { |
84 | | - const posture = data.createdItemCount > 0 ? "write-capable" : "read-only"; |
85 | | - const lines = []; |
86 | | - |
87 | | - lines.push("<details>"); |
88 | | - lines.push("<summary>Observability</summary>"); |
89 | | - lines.push(""); |
90 | | - |
91 | | - if (data.workflowName) { |
92 | | - lines.push(`- **workflow**: ${data.workflowName}`); |
93 | | - } |
94 | | - if (data.engineId) { |
95 | | - lines.push(`- **engine**: ${data.engineId}`); |
96 | | - } |
97 | | - if (data.traceId) { |
98 | | - lines.push(`- **trace id**: ${data.traceId}`); |
99 | | - } |
100 | | - |
101 | | - lines.push(`- **posture**: ${posture}`); |
102 | | - lines.push(`- **created items**: ${data.createdItemCount}`); |
103 | | - lines.push(`- **blocked requests**: ${data.blockedRequests}`); |
104 | | - lines.push(`- **agent output errors**: ${data.outputErrorCount}`); |
105 | | - lines.push(`- **firewall enabled**: ${data.firewallEnabled}`); |
106 | | - lines.push(`- **staged**: ${data.staged}`); |
107 | | - |
108 | | - if (data.createdItemTypes.length > 0) { |
109 | | - lines.push("- **item types**:"); |
110 | | - for (const itemType of data.createdItemTypes) { |
111 | | - lines.push(` - ${itemType}`); |
112 | | - } |
113 | | - } |
114 | | - |
115 | | - lines.push(""); |
116 | | - lines.push("</details>"); |
117 | | - |
118 | | - return lines.join("\n") + "\n"; |
119 | | -} |
| 5 | +const { buildObservabilitySummary, collectRuntimeObservabilityData } = require("./runtime_observability.cjs"); |
120 | 6 |
|
121 | 7 | async function main(core) { |
122 | 8 | await exportCopilotOtelTraces(core); |
123 | | - const data = collectObservabilityData(); |
| 9 | + const data = collectRuntimeObservabilityData(); |
124 | 10 | const markdown = buildObservabilitySummary(data); |
125 | 11 | await core.summary.addRaw(markdown).write(); |
126 | 12 | core.info("Generated observability summary in step summary"); |
127 | 13 | } |
128 | 14 |
|
129 | 15 | module.exports = { |
130 | 16 | buildObservabilitySummary, |
131 | | - collectObservabilityData, |
| 17 | + collectObservabilityData: collectRuntimeObservabilityData, |
132 | 18 | main, |
133 | 19 | }; |
0 commit comments