You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(tracing): opt-in Application Insights / OpenTelemetry support (#42)
Wires azure-monitor-opentelemetry as an opt-in [tracing] extra. When APPLICATIONINSIGHTS_CONNECTION_STRING is set, src.common.tracing.configure_tracing() initialises Azure Monitor and instruments FastAPI + httpx + logging spans; otherwise it is a no-op so the offline path is unaffected.
Bicep gains an enableAppInsights switch that provisions a workspace-based App Insights resource and injects the connection string + OTEL_SERVICE_NAME via Container App secrets. Docker image now installs the [tracing] extra by default so cloud deployments work out of the box.
Closes the v0.8 roadmap item.
Copy file name to clipboardExpand all lines: README.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,6 +60,8 @@ One `Deploy to Azure` click → Container Apps (scale-to-zero, < $5/month idle)
60
60
|`GREYNOISE_API_KEY`|`/greynoise/*`| Free Community key from <https://viz.greynoise.io/signup> → *Account → API Key*. Required for GreyNoise classification. |
61
61
|`ABUSEIPDB_API_KEY`|`/abuseipdb/*`| Free key from <https://www.abuseipdb.com/register> → *API → Create Key* (1000 req/day). Required for AbuseIPDB checks. |
62
62
|`OTX_API_KEY`|`/otx/*`| Free key from <https://otx.alienvault.com/> → *Settings → API Integration*. Required for AlienVault OTX indicator lookups. |
63
+
|`APPLICATIONINSIGHTS_CONNECTION_STRING`| All routes (tracing) | Optional. When set, the app initialises [Azure Monitor OpenTelemetry](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable?tabs=python) and ships FastAPI / `httpx` / logging spans to Application Insights. Leave unset to keep the stack fully offline. The Bicep template can provision an App Insights resource and inject this automatically — pass `enableAppInsights=true`. |
64
+
|`OTEL_SERVICE_NAME`| Tracing | Optional override for the OpenTelemetry `service.name` resource attribute. Defaults to `copilot-mcp-soc-pack`. |
63
65
64
66
> **Conditional registration**: Tools requiring an upstream key
65
67
> (`abusech`, `greynoise`, `abuseipdb`, `otx`) are registered **only**
@@ -232,7 +234,7 @@ See [mcp-client-config/](./mcp-client-config/) for ready-to-use configurations.
232
234
-[x] v0.5 AlienVault OTX + Have I Been Pwned, smoke harness, `#ExamplePrompts` planner hints, **Public Preview**
233
235
-[x] v0.6 Reliability hardening (httpx retries with backoff, LRU-bounded TTL cache, `/ready` probe), per-tool unit tests, mypy in CI, Dependabot, single-source version, PR-based workflow
234
236
-[x] v0.7 OSV.dev + CIRCL hashlookup + MITRE D3FEND, full upstream-retry coverage across every tool, codified `request_with_retry` convention
-[ ] v1.0 Hardening (Managed Identity inbound, custom metrics, Sentinel Workbook), GA based on Preview feedback
237
239
238
240
## Known limitations
@@ -242,7 +244,7 @@ This is a **Public Preview**. The following are intentional gaps today; PRs and
242
244
-**Inbound auth is API key only.** No Managed Identity, no Entra ID inbound, no per-caller RBAC. Rotate the shared `MCP_SOC_PACK_API_KEY` regularly.
243
245
-**In-memory TTL cache only.** Cache resets on every cold start (which is expected at scale-to-zero). v0.6 added an LRU eviction cap (default 1024 entries) so long-running replicas no longer leak memory; there is still no Redis or shared cache across replicas.
244
246
-**Single region.** The `Deploy to Azure` button provisions one Container Apps environment. There is no multi-region active-active sample yet.
245
-
-**Observability is logs only.** Container App logs land in a Log Analytics workspace; there are no custom metrics, traces, or a Workbook yet.
247
+
-**Observability ships logs + opt-in traces.** Container App logs land in a Log Analytics workspace. Application Insights distributed tracing is opt-in via `APPLICATIONINSIGHTS_CONNECTION_STRING` (or the Bicep `enableAppInsights=true` switch). There are no custom metricsor a packaged Sentinel Workbook yet.
246
248
-**`/health` and `/openapi.json` are intentionally un-authenticated** to support Container App probes and OpenAPI ingestion. Restrict ingress (Front Door, IP allow-list, private endpoint) if this is unacceptable.
247
249
-**OpenAPI is downgraded to 3.0.1 at runtime.** Microsoft Security Copilot rejects 3.1; downstream tools that rely on 3.1 features should consume the FastAPI source instead of `/openapi.json`.
Copy file name to clipboardExpand all lines: deploy/azuredeploy.json
+36-5Lines changed: 36 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -4,8 +4,8 @@
4
4
"metadata": {
5
5
"_generator": {
6
6
"name": "bicep",
7
-
"version": "0.42.1.51946",
8
-
"templateHash": "678075599944877869"
7
+
"version": "0.41.2.15936",
8
+
"templateHash": "16082163654774733647"
9
9
}
10
10
},
11
11
"parameters": {
@@ -67,6 +67,13 @@
67
67
"description": "Free AlienVault OTX API key (https://otx.alienvault.com/, Settings -> API Integration). Required for /otx/* endpoints. Leave empty to disable."
68
68
}
69
69
},
70
+
"enableAppInsights": {
71
+
"type": "bool",
72
+
"defaultValue": false,
73
+
"metadata": {
74
+
"description": "Provision a workspace-based Application Insights resource and inject APPLICATIONINSIGHTS_CONNECTION_STRING into the container. Requires the image to ship the optional `tracing` extra (default image does)."
@description('Free AlienVault OTX API key (https://otx.alienvault.com/, Settings -> API Integration). Required for /otx/* endpoints. Leave empty to disable.')
36
36
@secure()
37
37
paramotxApiKeystring = ''
38
+
@description('Provision a workspace-based Application Insights resource and inject APPLICATIONINSIGHTS_CONNECTION_STRING into the container. Requires the image to ship the optional `tracing` extra (default image does).')
39
+
paramenableAppInsightsbool = false
38
40
@description('Minimum number of replicas. Set 0 for scale-to-zero.')
The SOC Pack ships an **opt-in**[Azure Monitor OpenTelemetry](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable?tabs=python) integration that emits FastAPI HTTP server spans, outbound `httpx` client spans, and structured logs to Application Insights. It is **disabled by default** — leaving the connection string unset keeps the stack fully offline.
4
+
5
+
## What gets instrumented
6
+
7
+
`src/common/tracing.py` calls `azure.monitor.opentelemetry.configure_azure_monitor()` plus `FastAPIInstrumentor.instrument_app()`. With those two switches you get:
8
+
9
+
- One server span per inbound HTTP request to any FastAPI route (including `/openapi.json` and the `/mcp/` SSE endpoint).
10
+
- One client span per outbound call made through the shared `httpx.AsyncClient` in `src/common/http.py` (so every upstream call to KEV, EPSS, abuse.ch, OTX, OSV, ransomware.live, etc. is traced).
11
+
- Standard `logging` records emitted by the app are forwarded as Application Insights traces.
12
+
13
+
The `service.name` resource attribute defaults to `copilot-mcp-soc-pack` and can be overridden with `OTEL_SERVICE_NAME`.
14
+
15
+
## Enabling tracing
16
+
17
+
### 1. Bicep (recommended)
18
+
19
+
`deploy/main.bicep` now supports a `enableAppInsights` parameter. When set to `true` it provisions a workspace-based Application Insights resource backed by the same Log Analytics workspace, then injects `APPLICATIONINSIGHTS_CONNECTION_STRING` and `OTEL_SERVICE_NAME` into the Container App as a secret-backed env var pair.
20
+
21
+
```bash
22
+
az deployment group create \
23
+
--resource-group rg-copilot-mcp-soc-pack \
24
+
--template-file deploy/main.bicep \
25
+
--parameters apiKey=$(openssl rand -hex 32) \
26
+
enableAppInsights=true
27
+
```
28
+
29
+
### 2. Bring-your-own connection string
30
+
31
+
If you already have an Application Insights resource (or are running outside Bicep), set the env var directly on the Container App / your local shell:
The published Docker image (`ghcr.io/nobufumimurata/copilot-mcp-soc-pack:latest`) is already built with the `[tracing]` extra, so no extra install steps are needed in the cloud. For local installs from source, use `pip install ".[tracing]"`.
40
+
41
+
## Verifying it works
42
+
43
+
After enabling tracing and triggering a couple of requests (`scripts/smoke.ps1` or any tool call), open the App Insights resource in the Azure portal and check:
44
+
45
+
-**Application map**: `copilot-mcp-soc-pack` should appear with downstream nodes for each upstream API hostname (e.g. `api.first.org`, `urlhaus-api.abuse.ch`).
46
+
-**Transaction search → Dependencies**: filter by `target` to see per-upstream latency and HTTP status counts.
47
+
-**Failures**: any 4xx/5xx surfaced by `request_with_retry` will show up here with the retry count visible in the span attributes.
48
+
49
+
A useful KQL starter query (in the App Insights Logs blade):
50
+
51
+
```kusto
52
+
dependencies
53
+
| where cloud_RoleName == "copilot-mcp-soc-pack"
54
+
| summarize count(), avg(duration), percentiles(duration, 50, 95) by target, resultCode
55
+
| order by count_ desc
56
+
```
57
+
58
+
## Disabling
59
+
60
+
Unset `APPLICATIONINSIGHTS_CONNECTION_STRING` (or set it to an empty string) and restart the app. `configure_tracing()` will log `Application Insights tracing disabled: APPLICATIONINSIGHTS_CONNECTION_STRING is not set.` at startup and skip all OpenTelemetry initialisation.
61
+
62
+
If you want to drop the dependency entirely, install without the extra (`pip install .` instead of `pip install ".[tracing]"`). The lazy import in `src/common/tracing.py` will detect the missing module and log a warning, but the app still starts normally.
0 commit comments