# Include Consumer Labels in Access Logs

Consumer labels are key-value pairs attached to [consumers](https://docs.api7.ai/api7-gateway/key-concepts/consumers-and-credentials.md) that can represent metadata such as department, organization, or service tier. By default, access logs only include the consumer username. This guide shows you how to include consumer labels in the gateway's access log for more granular traffic analysis.

## How It Works[​](#how-it-works "Direct link to How It Works")

The approach uses three components:

1. **Custom NGINX variable**: Declare a variable (e.g., `$consumer_company`) in the gateway configuration and set its default value.
2. **`serverless-pre-function`**: A global plugin that reads the consumer label and assigns it to the variable at runtime.
3. **Access log format**: The custom variable is included in the log output.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* A running API7 Gateway deployment.
* Access to the gateway's `config.yaml` configuration file.
* A [token from the Dashboard](https://docs.api7.ai/api7-gateway/reference/obtain-dashboard-token.md).

## Step 1: Declare the Custom Variable[​](#step-1-declare-the-custom-variable "Direct link to Step 1: Declare the Custom Variable")

In the gateway's `config.yaml`, declare a custom NGINX variable and set its default value. You can declare multiple variables for different labels:

conf/config.yaml

```
nginx_config:

  http_server_location_configuration_snippet: |

    set $consumer_company "-";
```

## Step 2: Update the Access Log Format[​](#step-2-update-the-access-log-format "Direct link to Step 2: Update the Access Log Format")

In the same configuration file, add the custom variable to the access log format:

conf/config.yaml

```
nginx_config:

  http:

    access_log_format: >-

      $remote_addr - $remote_user [$time_local] $http_host

      "$request" $status $body_bytes_sent $request_time

      "$http_referer" "$http_user_agent"

      $upstream_addr $upstream_status $upstream_response_time

      "$consumer_company"
```

Reload or restart the gateway for the configuration changes to take effect.

## Step 3: Assign the Variable with a Serverless Function[​](#step-3-assign-the-variable-with-a-serverless-function "Direct link to Step 3: Assign the Variable with a Serverless Function")

Configure `serverless-pre-function` as a global plugin to read the consumer label and assign it to the custom variable. Run the function in the `log` phase so it can read the consumer identified during authentication:

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/global_rules/serverless-pre-function?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "plugins": {

      "serverless-pre-function": {

        "phase": "log",

        "functions": [

          "return function (conf, ctx) ngx.var.consumer_company = ctx.consumer and ctx.consumer.labels and ctx.consumer.labels[\"company\"] or \"unknown\" end"

        ]

      }

    }

  }'
```

adc.yaml

```
global_rules:

  serverless-pre-function:

    phase: log

    functions:

      - >-

        return function (conf, ctx)

          ngx.var.consumer_company = ctx.consumer

            and ctx.consumer.labels

            and ctx.consumer.labels["company"]

            or "unknown"

        end
```

This command updates global rules only. Services, routes, and consumers stay in place. Global rules absent from the file are removed. Preview the diff:

```
adc diff -f adc.yaml \

  --include-resource-type global_rule
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type global_rule
```

The function reads the `company` label from the consumer. If the consumer does not have the label or no consumer is identified (e.g., unauthenticated requests), the value defaults to `"unknown"`.

## Step 4: Configure a Consumer and a Protected Route[​](#step-4-configure-a-consumer-and-a-protected-route "Direct link to Step 4: Configure a Consumer and a Protected Route")

Create a consumer with the `company` label and a key authentication credential, then expose a route protected by `key-auth`:

* Admin API
* ADC

```
# Create the consumer with a label

curl -k "https://localhost:7443/apisix/admin/consumers/john?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "username": "john",

    "labels": {

      "company": "smart-technology"

    }

  }'



# Add a key-auth credential

curl -k "https://localhost:7443/apisix/admin/consumers/john/credentials/primary-key?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "primary-key",

    "plugins": {

      "key-auth": {

        "key": "john-key"

      }

    }

  }'



# Create a service with the upstream

curl -k "https://localhost:7443/apisix/admin/services/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "consumer-label-demo",

    "upstream": {

      "type": "roundrobin",

      "nodes": [

        { "host": "httpbin.org", "port": 80, "weight": 1 }

      ]

    }

  }'



# Create a route protected by key-auth

curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "consumer-label-demo",

    "paths": ["/anything"],

    "service_id": "consumer-label-demo",

    "plugins": {

      "key-auth": {}

    }

  }'
```

adc.yaml

```
consumers:

  - username: john

    labels:

      company: smart-technology

      docs-example: john

    credentials:

      - name: primary-key

        type: key-auth

        config:

          key: john-key

services:

  - name: consumer-label-demo

    routes:

      - name: consumer-label-demo

        uris:

          - /anything

        plugins:

          key-auth: {}

    upstream:

      type: roundrobin

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    labels:

      docs-example: john
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --include-resource-type consumer \

  --label-selector docs-example=john
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --include-resource-type consumer \

  --label-selector docs-example=john
```

## Step 5: Verify[​](#step-5-verify "Direct link to Step 5: Verify")

Send a request with a valid consumer key:

```
curl -i "http://127.0.0.1:9080/anything" -H "apikey: john-key"
```

You should receive an `HTTP/1.1 200 OK` response. The access log entry includes the consumer label:

```
192.168.1.1 - - [18/Mar/2025:09:17:28 +0000] 127.0.0.1:9080 "GET /anything HTTP/1.1" 200 508 1.260 "-" "curl/8.6.0" 13.210.43.76:80 200 1.153 "smart-technology"
```

Send a request without a key:

```
curl -i "http://127.0.0.1:9080/anything"
```

The access log shows the default value:

```
192.168.1.1 - - [18/Mar/2025:09:18:27 +0000] 127.0.0.1:9080 "GET /anything HTTP/1.1" 401 52 0.000 "-" "curl/8.6.0" - - - "unknown"
```

## Alternative: Forward Labels as Headers[​](#alternative-forward-labels-as-headers "Direct link to Alternative: Forward Labels as Headers")

If you want consumer labels included in structured log entries from logging plugins (e.g., `http-logger`, `kafka-logger`), use the [`attach-consumer-label`](https://docs.api7.ai/hub/attach-consumer-label.md) plugin to map consumer labels to upstream request headers. The headers are then available as NGINX variables (e.g., `$http_x_consumer_company`) that any logging plugin's `log_format` can reference.

Update the route from [Step 4](#step-4-configure-a-consumer-and-a-protected-route) to add both plugins alongside `key-auth`. The example below uses a logging endpoint at `http://log-collector:8080/logs`:

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "consumer-label-demo",

    "paths": ["/anything"],

    "service_id": "consumer-label-demo",

    "plugins": {

      "key-auth": {},

      "attach-consumer-label": {

        "headers": {

          "X-Consumer-Company": "$company"

        }

      },

      "http-logger": {

        "uri": "http://log-collector:8080/logs",

        "log_format": {

          "consumer_company": "$http_x_consumer_company"

        }

      }

    }

  }'
```

adc.yaml

```
services:

  - name: consumer-label-demo

    routes:

      - name: consumer-label-demo

        uris:

          - /anything

        plugins:

          key-auth: {}

          attach-consumer-label:

            headers:

              X-Consumer-Company: "$company"

          http-logger:

            uri: http://log-collector:8080/logs

            log_format:

              consumer_company: "$http_x_consumer_company"

    upstream:

      type: roundrobin

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    labels:

      docs-example: john
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=john
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=john
```

The `$` prefix in `attach-consumer-label` references a consumer label key. Requests from authenticated consumers will have the corresponding header injected before reaching the upstream and the logging plugin.

## Additional Resources[​](#additional-resources "Direct link to Additional Resources")

* [Consumers and Credentials](https://docs.api7.ai/api7-gateway/key-concepts/consumers-and-credentials.md)
* [Logging](https://docs.api7.ai/api7-gateway/observability/logging.md)
