Skip to content

graph2otel

graph2otel turns Microsoft 365 security and operations data into OpenTelemetry-native metrics and logs and pushes it over OTLP to Grafana Cloud or any compatible backend. It covers Entra ID, Intune, Microsoft 365, Purview, Defender XDR, Defender for Cloud Apps, and Exchange Online. One static binary can poll multiple tenants; there is no Prometheus endpoint to expose or scrape.

v1.0.0 is released and production-tested. The registry currently exposes 170 logical collectors. The generated collector reference is the authoritative inventory: its contents and the collector census are checked against the same 7 registration paths used by the application.

What it collects

The data plane has two deliberate output shapes:

  • Bounded, tenant-shaped aggregates become metrics. Directory inventory, license posture, device compliance, policy state, and similar snapshots are counted by bounded dimensions. A user, device, or event identifier never becomes a metric label.
  • Per-entity and event detail becomes logs. Sign-ins, audits, risk detections, managed-device records, policy details, and other individual records retain the fields operators need to investigate them. Watermarked streams are checkpointed and deduped where the source supplies an identifier.

All signals carry tenant_id. Logs also carry ingest_transport, so a backend can distinguish Graph polling, Azure Storage, the O365 activity feed, audit queries, and report exports without changing the event contract.

Ingest shapes

Microsoft does not expose one consistent API, so graph2otel ships 4 ingest engine shapes behind the same collector and telemetry interfaces:

  1. Graph REST polling reads current-state snapshots and watermark-window log endpoints. The window pollers use overlap plus seen-ID dedupe because those endpoints have no delta cursor.
  2. Asynchronous export jobs create, poll, and download Microsoft 365 audit-query and Intune report-export jobs.
  3. Azure Storage blob ingest consumes diagnostic-settings append blobs by byte offset. It covers signals with no Graph endpoint and can replace selected Graph log pollers with a more scalable transport. It is opt-in per tenant; see Blob ingest.
  4. The Office 365 Management Activity API manages subscriptions, lists content blobs, and downloads the unified audit records in them. This stable v1.0 source is the default M365 audit transport; see O365 Management Activity API.

The process can also call the domain-specific MDCA portal, Exchange Online admin, and Defender advanced-hunting surfaces through their collector registration paths. The architecture reference documents the composition seams; the collector reference names the exact source and permissions for every collector.

What it does not replace

graph2otel removes the need for a Log Analytics workspace or Event Hub for the signals it supports, but some supported signals still originate in Azure Monitor diagnostic settings. For example, MicrosoftGraphActivityLogs, Graph notification activity, and Intune compliance fired events have no Graph read endpoint; configure diagnostic settings to Azure Storage and let graph2otel's blob engine consume them.

The M365 unified audit stream is not a diagnostic-settings dependency: m365.activity reads it directly from the Office 365 Management Activity API. Entra Global Secure Access posture is also collected, while the separate GSA traffic-log endpoint remains unimplemented pending a live-verified response shape. ADFS sign-in logs and any other category absent from the generated collector reference still need their existing export path.

Use the collector reference, rather than a broad product-category claim, to decide whether a specific signal is covered.

Packaging

Every tagged release publishes:

  • a signed multi-architecture container at ghcr.io/rknightion/graph2otel;
  • Linux, macOS, and Windows binaries, checksums, per-archive SBOMs, a Sigstore bundle, and build provenance on the GitHub release;
  • an OCI Helm chart at oci://ghcr.io/rknightion/charts/graph2otel.

Start with Getting Started for container, Helm, and binary installation plus a local stdout smoke test.

References

Source, issues, and release history live at github.com/rknightion/graph2otel.