/docs/windows-event-logs
windowseventlog receiver
free plan / 1 gb-mo
telemtra.io
// collector guide

Windows Event Logs with
OpenTelemetry Collector.

Run otelcol-contrib.exe directly on Windows to ship Event Viewer logs and host metrics to Telemtra over OTLP.

Requirements

Use OpenTelemetry Collector Contrib on Windows. The core collector does not include the Windows Event Log receiver. Download otelcol-contrib.exe from the OpenTelemetry Collector releases and run it from PowerShell.

On Windows you run the collector directly on the host - there is no Linux Docker /hostfs mount, so host metrics do not need a root_path.

API key injection

Telemtra authenticates every OTLP request with a single header, x-api-key. Create the key in the Telemtra app under workspace settings → API keys, then inject it into the exporter through an environment variable so the key is never hardcoded in the config file:

exporters:
  otlp/telemtra:
    endpoint: ingest.telemtra.io:443
    headers:
      x-api-key: ${env:TELEMTRA_API_KEY}

Set the environment variable in the same PowerShell session before you start the collector:

$env:TELEMTRA_API_KEY = "tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

The ${env:TELEMTRA_API_KEY} reference is resolved by the collector at startup. To run the key as a Windows Service, set TELEMTRA_API_KEY as a machine or service environment variable instead of a session variable.

Event logs config

Windows Event Logs are structured. The windowseventlog receiver reads a channel and preserves stable fields such as event ID, provider, computer, channel, and account names so they can be searched, grouped, and alerted on in Telemtra. Save this as windows-event-log.yaml:

receivers:
  windowseventlog/application:
    channel: application
    start_at: end

processors:
  transform:
    error_mode: ignore
    log_statements:
      - context: log
        statements:
          # Core Windows Event attributes
          - set(attributes["event.id"], body["event_id"]["id"]) where IsMap(body["event_id"])
          - set(attributes["event.provider"], body["provider"]["name"]) where IsMap(body["provider"])
          - set(attributes["event.channel"], body["channel"]) where body["channel"] != nil
          - set(attributes["event.record_id"], body["record_id"]) where body["record_id"] != nil
          - set(attributes["event.task"], body["task"]) where body["task"] != nil
          - set(attributes["event.opcode"], body["opcode"]) where body["opcode"] != nil
          - set(attributes["event.keywords"], body["keywords"]) where body["keywords"] != nil
          # Flatten maps only; preserve other payload shapes before replacing body.
          - merge_maps(attributes, body["event_data"], "upsert") where IsMap(body["event_data"])
          - set(attributes["event.data"], body["event_data"]) where body["event_data"] != nil and not IsMap(body["event_data"])
          - merge_maps(attributes, body["user_data"]["data"], "upsert") where IsMap(body["user_data"]) and IsMap(body["user_data"]["data"])
          - set(attributes["event.user_data"], body["user_data"]) where body["user_data"] != nil
          # Drop duplicate anonymous Windows EventData fields.
          - delete_key(attributes, "param1") where attributes["param1"] != nil

          # Severity normalization
          - set(severity_text, "DEBUG") where body["level"] == "Verbose"
          - set(severity_number, 5) where body["level"] == "Verbose"
          - set(severity_text, "INFO") where body["level"] == "Information" or body["level"] == "Success Audit"
          - set(severity_number, 9) where body["level"] == "Information" or body["level"] == "Success Audit"
          - set(severity_text, "WARN") where body["level"] == "Warning" or body["level"] == "Failure Audit"
          - set(severity_number, 13) where body["level"] == "Warning" or body["level"] == "Failure Audit"
          - set(severity_text, "ERROR") where body["level"] == "Error"
          - set(severity_number, 17) where body["level"] == "Error"
          - set(severity_text, "FATAL") where body["level"] == "Critical"
          - set(severity_number, 21) where body["level"] == "Critical"

          # Replace giant object with actual message
          - set(body, body["message"]) where body["message"] != nil

  resource:
    attributes:
      - key: service.name
        value: windows-event-viewer
        action: upsert
      - key: deployment.environment
        value: production
        action: upsert

  batch:
    send_batch_size: 1000
    timeout: 10s

exporters:
  otlp/telemtra:
    endpoint: ingest.telemtra.io:443
    headers:
      x-api-key: ${env:TELEMTRA_API_KEY}

service:
  pipelines:
    logs:
      receivers: [windowseventlog/application]
      processors: [transform, resource, batch]
      exporters: [otlp/telemtra]

To collect more channels, add receivers like windowseventlog/security (channel: Security) and windowseventlog/system (channel: System) and list them in the logs pipeline alongside the application receiver. Once events are flowing, the Windows Event IDs reference covers which IDs in each channel are worth alerting on and which properties to filter.

Severity and fields

The windowseventlog receiver emits each event as a large structured JSON object in the log body. The transform processor above uses OTTL statements to turn that raw object into clean, searchable telemetry before it leaves the host. It does three things:

  • Promotes core event fields to attributes. Event ID, provider, channel, record ID, task, opcode, and keywords are copied to stable event.* attributes so they can be filtered, grouped, and used in alerts. Map-valued event_data and user_data.data are flattened into attributes with merge_maps. Other event_data shapes are preserved in event.data, and the complete user_data is preserved in event.user_data, and the anonymous param1 duplicate is dropped.
  • Normalizes severity. Windows levels are mapped to OpenTelemetry severity so Telemtra colors and filters them correctly: Verbose → DEBUG, Information / Success Audit → INFO, Warning / Failure Audit → WARN, Error → ERROR, and Critical → FATAL. Each rule sets both severity_text and the numeric severity_number.
  • Replaces the body with the rendered message. The final statement swaps the giant raw object for body.message, so the log body in Telemtra reads as the human message while the structured detail lives in attributes.

Event payload types vary by Windows provider. A non-null value can be a string rather than a map; IsMap guards prevent merge_maps from failing on these events. Explicit error_mode: ignore logs unexpected transformation errors and continues processing. Apply these changes to the collector configuration on each Windows host and restart that collector; updating the ingest server alone does not change host configurations. Receiver retries cannot repair a deterministic type error.

Order matters: transform runs before resource and batch in the pipeline so it can read the raw event body before anything else touches it.

Host metrics config

Use the hostmetrics receiver for Windows CPU, memory, disk, filesystem, network, paging, and process metrics. The processes scraper emits metrics such as system.processes.count when supported on the host. Save this as windows-host-metrics.yaml:

receivers:
  hostmetrics:
    collection_interval: 30s
    scrapers:
      cpu:
      memory:
      disk:
      filesystem:
        metrics:
          system.filesystem.utilization:
            enabled: true
      network:
      paging:
      processes:

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 512

  resource/host:
    attributes:
      - key: service.name
        value: windows-host
        action: upsert
      - key: host.name
        value: THINKPAD
        action: upsert
      - key: deployment.environment
        value: production
        action: upsert

  batch:
    timeout: 1s
    send_batch_size: 1024

exporters:
  otlp/telemtra:
    endpoint: ingest.telemtra.io:443
    headers:
      x-api-key: ${env:TELEMTRA_API_KEY}

service:
  pipelines:
    metrics:
      receivers: [hostmetrics]
      processors: [memory_limiter, resource/host, batch]
      exporters: [otlp/telemtra]

Replace host.name: THINKPAD with the machine name you use in operations, and set deployment.environment to the scope you want.

Run the collector

From PowerShell, set the API key, then start the collector with the config you want:

$env:TELEMTRA_API_KEY = "tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
.\otelcol-contrib.exe --config .\windows-event-log.yaml

If the collector fails because 127.0.0.1:8888 is already in use, another collector instance is running. Find and stop it:

Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 8888 |
  Select-Object LocalPort,OwningProcess

Stop-Process -Id <pid>

Verify

Generate a test Application event from an Administrator PowerShell:

New-EventLog -LogName Application -Source TelemtraSmokeTest -ErrorAction SilentlyContinue
Write-EventLog -LogName Application -Source TelemtraSmokeTest -EventId 1001 -EntryType Information -Message "Telemtra Windows Event Viewer smoke test"

In Telemtra, Logs should show service windows-event-viewer. Event records arrive as structured JSON bodies; the rendered message is in body.message. Host metrics appear under service windows-host for your machine.

Fields

  • service.name becomes the service selector - use a stable value like windows-event-viewer or windows-host, not the machine name.
  • host.name becomes the host selector shared by logs, traces, metrics, alerts, and dashboards - this is where the machine identity belongs.
  • deployment.environment becomes the environment selector.

Now that events are flowing, see which Event IDs to monitor and alert on. For Linux hosts, see Linux host observability. For OTLP transport details, see What is OTLP? New to Telemtra? The quickstart walks the minimum config for every supported stack. Create a workspace to get an API key.