# Map to UDM

This guide shows you how to map events to Google SecOps Unified Data Model (UDM) records in TQL. You’ll learn how to choose a UDM event type, populate metadata, model participants as UDM nouns, convert enum values, and preserve unmapped source fields.

Send structured UDM records

Tenzir’s [`to_google_secops`](https://preview.docs.tenzir.com/407/reference/operators/to_google_secops.md) operator can send structured UDM records to Google SecOps. Use `mode="udm_event"` for UDM event rows, or `mode="udm_entity"` for UDM entity rows.

The TQL examples in this guide build API-facing UDM records, so they use lowerCamelCase ingestion object field names such as `metadata.eventType` and `network.ipProtocol`.

## Use the UDM skill

Install the `tenzir-udm` skill when you want an agent to help with UDM schema decisions. See [Use agent skills](https://preview.docs.tenzir.com/407/guides/ai-workbench/use-agent-skills.md#use-the-udm-skill) for installation and usage examples.

Ask the agent to use ingestion object field names when it maps logs into UDM event or entity objects for Google SecOps UDM API ingestion. When generated UDM field headings show two forms, choose the right-side lowerCamelCase ingestion object form. For example, use `metadata.eventType` and `network.ipProtocol` in the TQL output. If a heading has one name, use that spelling.

## Choose the UDM event type

Start by choosing `metadata.eventType`. This value describes the activity that the event records, not the product that emitted the log. For example, a firewall connection log maps to `NETWORK_CONNECTION`, while DNS payloads map to `NETWORK_DNS`.

For a `NETWORK_CONNECTION` event, UDM expects these core sections:

* `metadata`: The event timestamp and product context.
* `principal`: The machine that initiated the network connection.
* `target`: The destination machine if it differs from the principal.
* `network`: The protocol, ports, byte counts, and other connection details.

## Write a small mapping

The following example shows a package mapper that maps a parsed firewall connection event to UDM. It keeps all mapping work inside the `event` argument, puts the source data under `fw`, moves one-use fields into UDM, converts source strings to UDM enum values, and preserves unmapped residue in `additional`.

```tql
---
args:
  named:
    - name: event
      description: The field that holds the event to map.
      type: field
      default: this
---


$event = {...$event, fw: $event, udm: {}}


let $ip_protocols = {
  tcp: "TCP",
  udp: "UDP",
  icmp: "ICMP",
}


let $actions = {
  allow: "ALLOW",
  allowed: "ALLOW",
  deny: "BLOCK",
  denied: "BLOCK",
  block: "BLOCK",
  blocked: "BLOCK",
}


$event.udm.metadata = {
  eventTimestamp: move $event.fw.ts,
  eventType: "NETWORK_CONNECTION",
  vendorName: "Example Networks",
  productName: "Example Firewall",
  productEventType: $event.fw.action,
}


$event.udm.principal = {
  ip: [move $event.fw.src_ip],
  port: move $event.fw.src_port,
}


$event.udm.target = {
  ip: [move $event.fw.dst_ip],
  port: move $event.fw.dst_port,
}


$event.udm.network = {
  ipProtocol: $ip_protocols[(move $event.fw.proto).to_lower()]? else "UNKNOWN_IP_PROTOCOL",
  sentBytes: move $event.fw.bytes_out,
  receivedBytes: move $event.fw.bytes_in,
}


$event.udm.securityResult = [{
  action: [$actions[$event.fw.action.to_lower()]? else "UNKNOWN_ACTION"],
  actionDetails: move $event.fw.action,
}]


$event = {...$event.udm, additional: $event.fw}
```

A call with a firewall event such as `{ts: 2024-01-15T10:30:45Z, action: "allowed", src_ip: "10.0.0.5", src_port: 51544, dst_ip: "203.0.113.10", dst_port: 443, proto: "tcp", bytes_out: 1280, bytes_in: 8192}` produces a UDM event like this:

```tql
{
  metadata: {
    eventTimestamp: 2024-01-15T10:30:45Z,
    eventType: "NETWORK_CONNECTION",
    vendorName: "Example Networks",
    productName: "Example Firewall",
    productEventType: "allowed",
  },
  principal: {
    ip: [
      "10.0.0.5",
    ],
    port: 51544,
  },
  target: {
    ip: [
      "203.0.113.10",
    ],
    port: 443,
  },
  network: {
    ipProtocol: "TCP",
    sentBytes: 1280,
    receivedBytes: 8192,
  },
  securityResult: [
    {
      action: [
        "ALLOW",
      ],
      actionDetails: "allowed",
    },
  ],
  additional: {},
}
```

## Apply the mapping pattern

Use the same structure for larger mappings:

* **Use the event scope**: Package mappers accept a named `event` field argument with `default: this`, create source and target namespaces with an initial spread, and mutate only fields below `$event`.
* **Keep a source namespace**: Keep the parsed event under a short namespace such as `fw`, `dns`, `edr`, or `event` before you create UDM fields.
* **Set `metadata.eventType` early**: Let the UDM event type drive which participant nouns and protocol fields you populate.
* **Model participants as nouns**: Use `principal` for the initiating entity, `target` for the destination, `observer` for the sensor, and `intermediary` for proxies or middleboxes.
* **Convert enum values explicitly**: Map source strings to UDM enum names such as `TCP`, `UDP`, `ALLOW`, or `BLOCK`.
* **Preserve unmapped fields**: Keep source fields that don’t have a deliberate UDM target under `additional` so reviewers can audit the mapping.

## See Also

* [`to_google_secops`](https://preview.docs.tenzir.com/407/reference/operators/to_google_secops.md)
* [Clean up values](https://preview.docs.tenzir.com/407/guides/normalization/clean-up-values.md)
* [Use agent skills](https://preview.docs.tenzir.com/407/guides/ai-workbench/use-agent-skills.md#use-the-udm-skill)
* [Map to ASIM](https://preview.docs.tenzir.com/407/guides/normalization/map-to-asim.md)
* [Map to CIM](https://preview.docs.tenzir.com/407/guides/normalization/map-to-cim.md)
* [Map to ECS](https://preview.docs.tenzir.com/407/guides/normalization/map-to-ecs.md)
* [Map to OCSF](https://preview.docs.tenzir.com/407/guides/normalization/map-to-ocsf.md)
* [Create a package](https://preview.docs.tenzir.com/407/guides/packages/create-a-package.md)
* [Write tests](https://preview.docs.tenzir.com/407/guides/testing/write-tests.md)