> ## Documentation Index
> Fetch the complete documentation index at: https://axiom.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# bag_keys

> This page explains how to use the bag_keys function in APL.

Use the `bag_keys` function in APL to extract the keys of a dynamic (bag) object as an array of strings. This is useful when you want to inspect or manipulate the structure of a dynamic field—such as JSON-like nested objects—without needing to know its exact schema in advance.

Use `bag_keys` when you’re working with semi-structured data and want to:

* Discover what properties are present in a dynamic object.
* Iterate over the keys programmatically using other array functions.
* Perform validation or debugging tasks to ensure all expected keys exist.

This function is especially helpful in log analytics, observability pipelines, and security auditing, where dynamic properties are often collected from various services or devices.

## For users of other query languages

If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL.

<AccordionGroup>
  <Accordion title="Splunk SPL users">
    In Splunk SPL, you typically interact with JSON-like fields using the `spath` command or use `keys(_raw)` to retrieve field names. In APL, `bag_keys` serves a similar purpose by returning an array of keys from a dynamic object.

    <CodeGroup>
      ```sql Splunk example theme={null}
      | eval key_list=keys(data_field)
      ```

      ```kusto APL equivalent theme={null}
      datatable(data: dynamic)
      [
          dynamic({ "ip": "127.0.0.1", "status": "200", "method": "GET" })
      ]
      | extend keys = bag_keys(data)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="ANSI SQL users">
    ANSI SQL doesn’t have native support for dynamic objects or JSON key introspection in the same way. However, some SQL dialects (like PostgreSQL or BigQuery) provide JSON-specific functions for extracting keys. `bag_keys` is the APL equivalent for dynamically introspecting JSON objects.

    <CodeGroup>
      ```sql SQL example theme={null}
      SELECT JSON_OBJECT_KEYS(data) FROM logs;
      ```

      ```kusto APL equivalent theme={null}
      datatable(data: dynamic)
      [
          dynamic({ "ip": "127.0.0.1", "status": "200", "method": "GET" })
      ]
      | extend keys = bag_keys(data)
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Usage

### Syntax

```kusto theme={null}
bag_keys(bag)
```

### Parameters

| Name  | Type      | Description                                        |
| ----- | --------- | -------------------------------------------------- |
| `bag` | `dynamic` | The dynamic object whose keys you want to extract. |

### Returns

An array of type `string[]` containing the names of the keys in the dynamic object. If the input isn’t a dynamic object, the function returns `null`.

## Use case examples

<Tabs>
  <Tab title="Log analysis">
    Use `bag_keys` to audit dynamic metadata fields in HTTP logs where each record contains a nested object representing additional request attributes.

    **Query**

    ```kusto theme={null}
    ['sample-http-logs']
    | extend metadata = dynamic({ 'os': 'Windows', 'browser': 'Firefox', 'device': 'Desktop' })
    | extend key_list = bag_keys(metadata)
    | project _time, uri, metadata, key_list
    ```

    [Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20metadata%20%3D%20dynamic\(%7B%20'os'%3A%20'Windows'%2C%20'browser'%3A%20'Firefox'%2C%20'device'%3A%20'Desktop'%20%7D\)%20%7C%20extend%20key_list%20%3D%20bag_keys\(metadata\)%20%7C%20project%20_time%2C%20uri%2C%20metadata%2C%20key_list%22%7D)

    **Output**

    | \_time              | uri    | metadata                                          | key\_list                    |
    | ------------------- | ------ | ------------------------------------------------- | ---------------------------- |
    | 2025-05-26 12:01:23 | /login | \{os: Windows, browser: Firefox, device: Desktop} | \[‘os’, ‘browser’, ‘device’] |

    This query inspects a simulated metadata object and returns the list of its keys, helping you debug inconsistencies or missing fields.
  </Tab>

  <Tab title="OpenTelemetry traces">
    Use `bag_keys` to examine custom span attributes encoded as dynamic fields within OpenTelemetry trace events.

    **Query**

    ```kusto theme={null}
    ['otel-demo-traces']
    | extend attributes = dynamic({ 'user_id': 'abc123', 'feature_flag': 'enabled' })
    | extend attribute_keys = bag_keys(attributes)
    | project _time, ['service.name'], kind, attributes, attribute_keys
    ```

    [Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'otel-demo-traces'%5D%20%7C%20extend%20attributes%20%3D%20dynamic\(%7B%20'user_id'%3A%20'abc123'%2C%20'feature_flag'%3A%20'enabled'%20%7D\)%20%7C%20extend%20attribute_keys%20%3D%20bag_keys\(attributes\)%20%7C%20project%20_time%2C%20%5B'service.name'%5D%2C%20kind%2C%20attributes%2C%20attribute_keys%22%7D)

    **Output**

    | \_time              | \['service.name'] | kind   | attributes                                  | attribute\_keys                |
    | ------------------- | ----------------- | ------ | ------------------------------------------- | ------------------------------ |
    | 2025-05-26 13:14:01 | frontend          | client | \{user\_id: abc123, feature\_flag: enabled} | \[‘user\_id’, ‘feature\_flag’] |

    This query inspects the custom span-level attributes and extracts their keys to verify attribute coverage or completeness.
  </Tab>

  <Tab title="Security logs">
    Use `bag_keys` to list all security-related fields captured dynamically during request monitoring for auditing or compliance.

    **Query**

    ```kusto theme={null}
    ['sample-http-logs']
    | extend security_context = dynamic({ 'auth_status': 'success', 'role': 'admin', 'ip': '192.168.1.5' })
    | extend fields = bag_keys(security_context)
    | project _time, status, ['geo.country'], security_context, fields
    ```

    [Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20security_context%20%3D%20dynamic\(%7B%20'auth_status'%3A%20'success'%2C%20'role'%3A%20'admin'%2C%20'ip'%3A%20'192.168.1.5'%20%7D\)%20%7C%20extend%20fields%20%3D%20bag_keys\(security_context\)%20%7C%20project%20_time%2C%20status%2C%20%5B'geo.country'%5D%2C%20security_context%2C%20fields%22%7D)

    **Output**

    | \_time              | status | \['geo.country'] | security\_context                                      | fields                          |
    | ------------------- | ------ | ---------------- | ------------------------------------------------------ | ------------------------------- |
    | 2025-05-26 15:32:10 | 200    | US               | \{auth\_status: success, role: admin, ip: 192.168.1.5} | \[‘auth\_status’, ‘role’, ‘ip’] |

    This helps you audit security metadata in requests and ensure key fields are present across records.
  </Tab>
</Tabs>

## List of related functions

* [bag\_pack](/apl/scalar-functions/array-functions/bag-pack): Converts a list of key-value pairs to a dynamic property bag. Use when you need to build a bag.
* [bag\_has\_key](/apl/scalar-functions/array-functions/bag-has-key): Checks whether a dynamic property bag contains a specific key.
