Skip to content

feat(logs): config-driven log transformations and static values for golden log lines - #2075

Open
AmitsinghTanwar007 wants to merge 4 commits into
mainfrom
feat/euler-log-structure
Open

feat(logs): config-driven log transformations and static values for golden log lines#2075
AmitsinghTanwar007 wants to merge 4 commits into
mainfrom
feat/euler-log-structure

Conversation

@AmitsinghTanwar007

@AmitsinghTanwar007 AmitsinghTanwar007 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Config-driven log transformations: Field renaming and nested JSON construction for golden log lines via [log.transformations.incoming] and [log.transformations.outgoing] config sections. Dotted target paths (e.g. "api_details.url") create nested JSON objects. Gated behind log-transformations feature flag.
  • Runtime static values (split by direction): [log.static_values.incoming] and [log.static_values.outgoing] inject separate key-value pairs into each golden log line. This allows different values for the same field — e.g. hostname = "euler-gateway" on incoming vs hostname = "connector-service" on outgoing. Overridable per-request via x-config-override header — no server restart needed.
  • transformation_mode: Controls whether event transformations copy or replace the original source fields ("copy" default, "replace" removes originals).
  • Deadlock fix: log_utils::Storage::record_value() calls tracing::warn! for reserved keys, which re-enters the subscriber while holding the span extensions write lock → deadlock. Fixed by filtering reserved keys before entering with_current_span_mut.

Config Format

# Static values — separate maps for incoming (gRPC handler) and outgoing (connector call) golden log lines
[log.static_values.incoming]
hostname = "euler-gateway"
schema_version = "V2"

[log.static_values.outgoing]
hostname = "connector-service"

# Log transformations (behind feature flag)
[log.transformations.incoming]
"connector" = "gateway"
"api_details.request_body" = "request_body"
"api_details.response_body" = "response_body"
"api_details.status_code" = "status_code"
"api_details.error" = "error_message"

[log.transformations.outgoing]
"api_details.url" = "request.url"
"api_details.method" = "request.method"
"api_details.request_headers" = "request.headers"
"api_details.request_body" = "request.body"
"api_details.response_body" = "response.body"
"api_details.response_headers" = "response.headers"
"api_details.status_code" = "response.status_code"
"api_details.error" = "response.error_message"
"api_details.latency" = "latency"

Test Plan

1. Build and run

cargo run --features "grpc-server/log-transformations" -p grpc-server

2. gRPC request (static values via header override)

grpcurl -plaintext \
  -import-path crates/types-traits/grpc-api-types/proto \
  -proto services.proto \
  -H "x-auth: body-key" \
  -H "x-connector: authorizedotnet" \
  -H "x-api-key: <REDACTED>" \
  -H "x-key1: <REDACTED>" \
  -H "x-merchant-id: test_merchant_001" \
  -H "x-request-id: req-test-123" \
  -H 'x-config-override: {"log":{"static_values":{"incoming":{"custom_hostname":"incoming-host"},"outgoing":{"custom_hostname":"outgoing-host","custom_key":"my-custom-value"}}}}' \
  -d '{
    "merchant_transaction_id": "test_123",
    "amount": {"minor_amount": 1000, "currency": "USD"},
    "payment_method": {
      "card": {
        "card_number": {"value": "4111111111111111"},
        "card_exp_month": {"value": "03"},
        "card_exp_year": {"value": "2030"},
        "card_cvc": {"value": "737"},
        "card_holder_name": {"value": "John Doe"}
      }
    },
    "capture_method": "AUTOMATIC",
    "address": {"billing_address": {}},
    "auth_type": "NO_THREE_DS",
    "return_url": "https://example.com/return",
    "merchant_request_id": "test_123"
  }' \
  localhost:8000 types.PaymentService/Authorize

3. Response

{
  "merchantTransactionId": "120087958932",
  "connectorTransactionId": "120087958932",
  "status": "CHARGED",
  "statusCode": 200,
  "networkTransactionId": "XUB15TGRX3P9358QTM7XAM4",
  "connectorResponse": {
    "additionalPaymentMethodData": {
      "card": {
        "paymentChecks": "eyJhdnNfcmVzdWx0X2NvZGUiOiJZIiwiZGVzY3JpcHRpb24iOiJUaGUgc3RyZWV0IGFkZHJlc3MgYW5kIHBvc3RhbCBjb2RlIG1hdGNoZWQuIn0="
      }
    }
  },
  "connectorReferenceId": "120087958932"
}

4. Outgoing golden log line

Shows api_details nested object from log transformations + custom_hostname/custom_key from outgoing static values:

{
  "message": "[EXECUTE_CONNECTOR_PROCESSING_STEP - EVENT] Outgoing Request completed",
  "level": "INFO",
  "tag": "OutgoingApi",
  "log_type": "api",
  "message_": "Golden Log Line (outgoing)",
  "custom_key": "my-custom-value",
  "custom_hostname": "outgoing-host",
  "latency": "2432",
  "gateway": "authorizedotnet",
  "api_details": {
    "url": "https://apitest.authorize.net/xml/v1/request.api",
    "method": "POST",
    "latency": "2432",
    "request_body": "{...}",
    "response_body": "{...}",
    "request_headers": "{...}",
    "response_headers": "{...}"
  }
}

5. Incoming golden log line

Shows connector field from incoming transformation + api_details nested object + incoming static values:

{
  "message": "[PAYMENT_AUTHORIZE - EVENT] Golden Log Line (incoming - response)",
  "level": "INFO",
  "message_": "Golden Log Line (incoming)",
  "connector": "authorizedotnet",
  "custom_hostname": "incoming-host",
  "api_details": {
    "request_body": "{...}",
    "response_body": "PaymentServiceAuthorizeResponse { ... }"
  }
}

Checks

  • cargo check -p grpc-server (without feature flag) — passes
  • cargo check --features "grpc-server/log-transformations" -p grpc-server — passes
  • End-to-end test with live connector call — transformations and static values appear in both golden log lines

Golden log incoming
Screenshot 2026-08-07 at 10 32 26 AM

Golden log outgoing
Screenshot 2026-08-07 at 10 32 59 AM

@AmitsinghTanwar007
AmitsinghTanwar007 requested review from a team as code owners August 7, 2026 04:58
…olden log lines

Add Euler-compatible log schema support:
- Config-driven field renaming for golden log lines via [log.transformations.incoming]
  and [log.transformations.outgoing] (gated behind log-transformations feature flag)
- Runtime static key-value pairs via [log.static_values], overridable per-request
  through x-config-override header
- transformation_mode (copy/replace) for event field transformations
- Deadlock fix: filter reserved keys before entering span write lock to prevent
  re-entrant deadlock from log_utils record_value calling tracing::warn!

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AmitsinghTanwar007
AmitsinghTanwar007 force-pushed the feat/euler-log-structure branch from 6fd0ca8 to 2ef6c3a Compare August 7, 2026 05:00
hyperswitch-bot Bot and others added 3 commits August 7, 2026 05:03
Auto-applied by CI:
- cargo +nightly fmt --all
- make -C sdk generate (if applicable)
- make docs (if applicable)

This commit was automatically generated by GitHub Actions.
Allows different static key-value pairs for incoming (gRPC handler) and
outgoing (connector call) golden log lines. Config format changes from
flat [log.static_values] to [log.static_values.incoming] and
[log.static_values.outgoing].
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant