Skip to content
If you are interested in trying out Gloo Gateway with the Kubernetes Gateway API, check out Solo Enterprise for kgateway. This version adds enterprise functionality on top of the kgateway open source project.

Enrich access logs

Page as Markdown

Use a transformation template to inject additional metadata to your access logs.

In this guide, you use an Inja function to extract an environment variable value from the gateway proxy pod and add this value to the dynamic metadata filter in Envoy. Then, you inject the value that you stored in the dynamic metadata filter when writing access logs.

Before you begin

  1. Get the external address of the gateway and save it in an environment variable.

    export INGRESS_GW_ADDRESS=$(kubectl get svc -n gloo-system gloo-proxy-http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
    echo $INGRESS_GW_ADDRESS  
    kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080

Enable access logs

  1. Create a ListenerOption resource to define your access logging rules. The following example writes access logs to the stdout stream of the gateway proxy container by using a custom string format that is defined in the jsonFormat field. If no custom string format is defined, the default Envoy format is used.

    kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: ListenerOption
    metadata:
      name: access-logs
      namespace: gloo-system
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: http
      options:
        accessLoggingService:
          accessLog:
          - fileSink:
              path: /dev/stdout
              jsonFormat:
                  start_time: "%START_TIME%"
                  method: "%REQ(X-ENVOY-ORIGINAL-METHOD?:METHOD)%"
                  path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
                  protocol: "%PROTOCOL%"
                  response_code: "%RESPONSE_CODE%"
                  response_flags: "%RESPONSE_FLAGS%"
                  bytes_received: "%BYTES_RECEIVED%"
                  bytes_sent: "%BYTES_SENT%"
                  total_duration: "%DURATION%"
                  resp_upstream_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
                  req_x_forwarded_for: "%REQ(X-FORWARDED-FOR)%"
                  user_agent: "%REQ(USER-AGENT)%"
                  request_id: "%REQ(X-REQUEST-ID)%"
                  authority: "%REQ(:AUTHORITY)%"
                  upstreamHost: "%UPSTREAM_HOST%"
                  upstreamCluster: "%UPSTREAM_CLUSTER%"
    EOF
  2. Send a request to the httpbin app on the www.example.com domain. Verify that your request succeeds and that you get back a 200 HTTP response code.

    curl -i http://$INGRESS_GW_ADDRESS:8080/status/200 -H "host: www.example.com:8080"
    curl -i localhost:8080/status/200 -H "host: www.example.com:8080"

    Example output:

    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    date: Fri, 07 Jun 2024 21:10:03 GMT
    x-envoy-upstream-service-time: 2
    server: envoy
    transfer-encoding: chunked
  3. Get the logs for the gateway pod and verify that you see an entry for each request that you sent to the httpbin app.

    kubectl -n gloo-system logs deployments/gloo-proxy-http | tail -1 | jq --sort-keys

    Example output:

    {
      "authority": "www.example.com:8080",
      "bytes_received": 0,
      "bytes_sent": 0,
      "method": "GET",
      "path": "/status/200",
      "protocol": "HTTP/1.1",
      "req_x_forwarded_for": null,
      "request_id": "a6758866-0f26-4c95-95d9-4032c365c498",
      "resp_upstream_service_time": "0",
      "response_code": 200,
      "response_flags": "-",
      "start_time": "2024-08-19T20:57:57.511Z",
      "total_duration": 1,
      "upstreamCluster": "kube-svc:httpbin-httpbin-8000_httpbin",
      "upstreamHost": "10.36.0.14:8080",
      "user_agent": "curl/7.77.0"
    }

Enrich access logs

  1. Create a RouteOption or VirtualHostOption resource with the following transformation rules:

    • The env Inja function is used to extract the POD_NAME environment variable from the gateway proxy pod.
    • The value of the environment variable is added to the pod_name key in the dynamic metadata values.
      kubectl apply -f- <<EOF
      apiVersion: gateway.solo.io/v1
      kind: RouteOption
      metadata:
        name: transformation
        namespace: httpbin
      spec:
        targetRefs:
        - group: gateway.networking.k8s.io
          kind: HTTPRoute
          name: httpbin
        options:
          transformations:
            requestTransformation:
              transformationTemplate:
                dynamicMetadataValues:
                # Set a dynamic metadata entry named "pod_name"
                - key: 'pod_name'
                  value:
                    # The POD_NAME env is set by default on the gateway-proxy pods
                    text: '{{ env("POD_NAME") }}'
      EOF
      kubectl apply -n gloo-system -f- <<EOF
      apiVersion: gateway.solo.io/v1
      kind: VirtualHostOption
      metadata:
        name: transformation
        namespace: gloo-system
      spec:
        options:
          transformations:
            requestTransformation:
              transformationTemplate:
                dynamicMetadataValues:
                # Set a dynamic metadata entry named "pod_name"
                - key: 'pod_name'
                  value:
                    # The POD_NAME env is set by default on the gateway-proxy pods
                    text: '{{ env("POD_NAME") }}'
        targetRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: http
          namespace: gloo-system
      EOF
  2. Update the ListenerOption resource to include the pod_name from the dynamic metadata values.

    kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: ListenerOption
    metadata:
      name: access-logs
      namespace: gloo-system
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: http
      options:
        accessLoggingService:
          accessLog:
          - fileSink:
              path: /dev/stdout
              jsonFormat:
                  start_time: "%START_TIME%"
                  method: "%REQ(X-ENVOY-ORIGINAL-METHOD?:METHOD)%"
                  path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
                  protocol: "%PROTOCOL%"
                  response_code: "%RESPONSE_CODE%"
                  response_flags: "%RESPONSE_FLAGS%"
                  bytes_received: "%BYTES_RECEIVED%"
                  bytes_sent: "%BYTES_SENT%"
                  total_duration: "%DURATION%"
                  resp_upstream_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
                  req_x_forwarded_for: "%REQ(X-FORWARDED-FOR)%"
                  user_agent: "%REQ(USER-AGENT)%"
                  request_id: "%REQ(X-REQUEST-ID)%"
                  authority: "%REQ(:AUTHORITY)%"
                  upstreamHost: "%UPSTREAM_HOST%"
                  upstreamCluster: "%UPSTREAM_CLUSTER%"
                  pod_name: '%DYNAMIC_METADATA(io.solo.transformation:pod_name)%'
    EOF
  3. Send another request to the httpbin app.

    curl -i http://$INGRESS_GW_ADDRESS:8080/status/200 -H "host: www.example.com:8080"
    curl -i localhost:8080/status/200 -H "host: www.example.com:8080"

  4. Review the access logs and verify that the pod_name is now injected into your access logs.

    kubectl -n gloo-system logs deployments/gloo-proxy-http | tail -1 | jq --sort-keys

    Example output:

    {
      "authority": "www.example.com:8080",
      "bytes_received": 0,
      "bytes_sent": 0,
      "method": "GET",
      "path": "/status/200",
      "pod_name": "gloo-proxy-http-844ff8bc4d-dh4pn",
      "protocol": "HTTP/1.1",
      "req_x_forwarded_for": null,
      "request_id": "132892e6-085e-400f-98da-c055ca04b714",
      "resp_upstream_service_time": "2",
      "response_code": 200,
      "response_flags": "-",
      "start_time": "2025-05-14T16:43:07.506Z",
      "total_duration": 2,
      "upstreamCluster": "kube-svc_httpbin-httpbin-8000_httpbin_httpbin_httpbin_8000",
      "upstreamHost": "10.0.12.250:8080",
      "user_agent": "curl/8.7.1"
    }

Cleanup

You can remove the resources that you created in this guide.

kubectl delete virtualhostoption transformation -n gloo-system
kubectl delete routeoption transformation -n httpbin
kubectl delete listeneroption access-logs -n gloo-system