DEV Community

Cover image for Escape Vendor Lock-in: Multi-Backend Log Delivery with OTel Collector for FSx for ONTAP.

Escape Vendor Lock-in: Multi-Backend Log Delivery with OTel Collector for FSx for ONTAP.

TL;DR

We shipped the same FSx for ONTAP audit logs to three backends simultaneously — Datadog, Grafana Cloud, and Honeycomb — without changing a single line of Lambda code. The OpenTelemetry Collector sits between our Lambda and the backends as a routing layer. Adding or removing a backend is a YAML config change, not a code deployment.

  • Same audit logs → 3 backends simultaneously
  • Zero Lambda code changes between backends (SHA-256 verified)
  • OTel Collector as the vendor-neutral routing layer
  • All 3 event sources work: FSx audit logs via S3 Access Point, EMS webhooks, FPolicy file operations

What We're Building

In Part 2, we built a Lambda that speaks Datadog's API directly. It works great — but what happens when your security team wants Splunk, your SRE team wants Grafana, and your platform team is evaluating Honeycomb?

You'd need three separate Lambdas, each with vendor-specific formatting, auth, and retry logic. That's vendor lock-in expressed as infrastructure.

The Problem: Vendor-Specific APIs = Lock-in

Every observability vendor has their own wire format:

Vendor Auth Header Payload Format Endpoint Pattern
Datadog DD-API-KEY: <key> Custom JSON schema https://http-intake.logs.{site}/api/v2/logs
Splunk Authorization: Splunk <token> HEC event wrapper https://<host>:8088/services/collector/event
Grafana Cloud Authorization: Basic <b64> OTLP https://otlp-gateway-prod-<region>.grafana.net/otlp
Honeycomb x-honeycomb-team: <key> OTLP https://api.honeycomb.io

If your Lambda speaks Datadog's API, switching to Grafana Cloud means rewriting your Lambda. That's the lock-in.

The Solution: OTLP as the Producer-to-Collector Contract

OpenTelemetry Protocol (OTLP) is the vendor-neutral producer-to-Collector contract. Our Lambda speaks OTLP — period. The OTel Collector handles routing, processing, and backend-specific export.

┌─────────────────────────────────────────────────────────────────────┐
│ AWS Account                                                         │
│                                                                     │
│  ┌──────────────┐     ┌──────────────────┐     ┌─────────────────┐  │
│  │ Audit Logs   │────▶│ Lambda           │     │ OTel Collector  │  │
│  │ (via S3 AP)  │────▶│ (OTLP Shipper)   │────▶│ (Docker/Fargate)│  │
│  │ EMS/FPolicy  │────▶│                  │     │                 │  │
│  └──────────────┘     └──────────────────┘     └─┬──────┬──────┬─┘  │
│                                                  │      │      │    │
└──────────────────────────────────────────────────┼──────┼──────┼────┘
                                                   │      │      │
                                                   ▼      ▼      ▼
                                              Datadog  Grafana Honeycomb
                                               (AP1)    Cloud    
Enter fullscreen mode Exit fullscreen mode

The Lambda sends OTLP/HTTP to the Collector. The Collector fans out to any combination of backends. Adding Honeycomb? Add 5 lines of YAML. Dropping Datadog? Remove 4 lines. No Lambda redeployment.

Prerequisites

Before starting, you need:

  1. FSx for ONTAP with audit logging configured (see Part 2 for setup)
  2. Docker installed locally (Colima works — see troubleshooting for compose compatibility)
  3. At least one backend account:
    • Datadog: API key + site (e.g., ap1.datadoghq.com)
    • Grafana Cloud: Instance ID + API token (Cloud Portal → OTLP)
    • Honeycomb: Ingest API key (starts with hcaik_)
  4. AWS account with Lambda deployment capability
  5. Parts 1–4 context (recommended but not required — this integration works standalone)

FSx for ONTAP S3 Access Point note: The Lambda reads audit logs through an S3 Access Point attached to the FSx for ONTAP volume. Data remains on the FSx file system — it is not copied to a separate S3 bucket. S3 API throughput via FSx depends on the file system's provisioned throughput capacity, not standard S3 scaling. Validate FSx read throughput separately from Collector and backend ingest throughput.

The OTel Collector Configuration

The Collector config is the heart of this pattern. Here's the full verified configuration for multi-backend delivery:

# otel-collector-config.yaml
# ✅ VERIFIED WORKING (2026-05-18)
# Image: otel/opentelemetry-collector-contrib:0.152.0
# Backends: Grafana Cloud (ap-northeast-0) + Honeycomb

receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318

processors:
  # memory_limiter:        # Recommended for production
  #   check_interval: 1s
  #   limit_mib: 512
  #   spike_limit_mib: 128
  batch:
    timeout: 5s
    send_batch_size: 1000

exporters:
  otlp_http/grafana:
    endpoint: ${env:GRAFANA_OTLP_ENDPOINT}
    headers:
      Authorization: "Basic ${env:GRAFANA_BASIC_AUTH}"

  otlp_http/honeycomb:
    endpoint: https://api.honeycomb.io
    headers:
      x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
      x-honeycomb-dataset: ${env:HONEYCOMB_DATASET}

extensions:
  health_check:
    endpoint: 0.0.0.0:13133

service:
  extensions: [health_check]
  pipelines:
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp_http/grafana, otlp_http/honeycomb]
Enter fullscreen mode Exit fullscreen mode

Depending on your Honeycomb environment and dataset model, x-honeycomb-dataset may be optional or handled differently. Refer to your Honeycomb OTLP setup page for the recommended configuration.

This article uses otlp_http (the forward-compatible component name). If your Collector version does not recognize it, use the older otlphttp alias or upgrade the Collector.

Section Breakdown

Section Purpose Key Settings
receivers.otlp Accepts OTLP/HTTP from Lambda Port 4318 (OTLP standard)
processors.batch Buffers logs before export 5s timeout OR 1000 records (whichever first)
exporters.otlp_http/* Sends to each backend Per-backend auth headers
extensions.health_check Liveness probe Port 13133 for curl -f checks
service.pipelines Wires components together logs: receiver → processor → exporters

Production note: This configuration is suitable for development and validation. For production, add retry_on_failure and sending_queue settings to exporters, configure memory_limiter processor, and consider persistent storage extensions. Without persistent buffering, telemetry in the Collector's in-memory batch can be lost during Collector restarts.

Adding Datadog as a Third Backend

To send to all three simultaneously, add the Datadog exporter:

exporters:
  # ... existing grafana + honeycomb exporters ...

  datadog:
    api:
      key: ${env:DD_API_KEY}
      site: ${env:DD_SITE}

service:
  pipelines:
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp_http/grafana, otlp_http/honeycomb, datadog]
Enter fullscreen mode Exit fullscreen mode

That's it. Restart the Collector. Same Lambda, same OTLP payload, now three destinations.

For Datadog, this example uses the Collector's dedicated datadog exporter rather than generic otlp_http, because it handles Datadog-specific intake behavior, metadata mapping, and host tagging.

The Lambda Handler (OTLP Shipper)

Key Design Decisions

  1. Why OTLP? — It gives the Lambda a single producer-to-Collector contract. The Collector then handles each backend's supported exporter or intake path. One format to maintain, not three.
  2. Why no vendor SDK? — SDKs add cold start latency, dependency management, and vendor coupling. Pure urllib3 + JSON keeps the Lambda lean.
  3. Why AUTH_MODE? — Different Collectors may need different auth. The Lambda supports none, basic, and bearer modes without code changes.

Field Mapping: FSx ONTAP → OTLP Attributes

The Lambda maps FSx ONTAP audit fields to semantic OTLP attribute keys:

FSx ONTAP Field OTLP Attribute Key Example Value
EventID event.type 4663
UserName user.name admin@corp.local
ClientIP client.address 10.0.1.50
Operation fsxn.operation ReadData
ObjectName fsxn.path /vol/data/reports/q4.xlsx
Result fsxn.result Success
SVMName fsxn.svm svm-prod-01

The examples above focus on S3 audit logs because they are the highest-volume path. The same OTLP shipper pattern is reused for EMS webhook events and FPolicy file operations using source-specific field mappers (ems_handler.py, fpolicy_handler.py), while preserving the same Collector-facing OTLP contract. For EMS and FPolicy, source-specific service names are used (fsxn-ems, fsxn-fpolicy) to distinguish event sources in the backend.

Resource-level attributes (set once per payload, not per log record):

Attribute Value Purpose
service.name fsxn-audit Service identification
cloud.provider aws Cloud context
cloud.platform aws_fsx Platform context

cloud.platform=aws_fsx is a project-specific value used to identify FSx for ONTAP as the data source. It is not part of the OpenTelemetry semantic conventions standard cloud.platform values (which include aws_ec2, aws_ecs, aws_eks, aws_lambda, etc.).

Severity Determination Logic

The Lambda determines OTLP severity from the Result field:

WARN_KEYWORDS = ("fail", "denied", "error")

def determine_severity(result: Optional[str]) -> tuple[int, str]:
    """Determine OTLP severity from FSx ONTAP Result field."""
    if not result:
        return (9, "INFO")
    lower = result.lower()
    for keyword in WARN_KEYWORDS:
        if keyword in lower:
            return (13, "WARN")
    return (9, "INFO")
Enter fullscreen mode Exit fullscreen mode

This means failed access attempts (Result: "Failure") automatically get severityNumber: 13 (WARN), making them easy to filter in any backend.

The Lambda sets both severityNumber and severityText according to the OpenTelemetry Logs Data Model severity level definitions.

OTLP Payload Construction

def build_otlp_payload(
    logs: list[dict[str, Any]],
    service_name: str,
    source_key: str,
) -> dict[str, Any]:
    """Build OTLP Log Data Model payload."""
    log_records = [map_log_record(log) for log in logs]

    return {
        "resourceLogs": [{
            "resource": {
                "attributes": [
                    {"key": "service.name", "value": {"stringValue": service_name}},
                    {"key": "cloud.provider", "value": {"stringValue": "aws"}},
                    {"key": "cloud.platform", "value": {"stringValue": "aws_fsx"}},
                ]
            },
            "scopeLogs": [{
                "scope": {"name": "fsxn-otel-shipper", "version": "1.0.0"},
                "logRecords": log_records,
            }],
        }]
    }
Enter fullscreen mode Exit fullscreen mode

No vendor SDK. No vendor-specific formatting. Just the OTLP Log Data Model.

Retry with Exponential Backoff

MAX_RETRIES = 3
BASE_INTERVAL = 2  # seconds

def _send_otlp_payload(payload, endpoint, auth_headers=None) -> bool:
    """Send OTLP payload via HTTP POST with retry logic.

    Retries on HTTP 429 and 5xx. Does not retry on 4xx (except 429).
    Exponential backoff: 2s, 4s, 8s with jitter.
    """
    url = f"{endpoint}/v1/logs"
    headers = {"Content-Type": "application/json"}
    if auth_headers:
        headers.update(auth_headers)

    json_body = json.dumps(payload).encode("utf-8")

    for attempt in range(MAX_RETRIES):
        response = http.request("POST", url, body=json_body, headers=headers, timeout=30.0)

        if response.status < 300:
            return True
        if response.status == 429 or response.status >= 500:
            wait_time = BASE_INTERVAL * (2 ** attempt) + random.uniform(0, 1)
            time.sleep(wait_time)
            continue
        # Client error (4xx except 429) — don't retry
        return False
    return False
Enter fullscreen mode Exit fullscreen mode

AUTH_MODE Support

The Lambda supports three authentication modes via the AUTH_MODE environment variable:

AUTH_MODE Behavior Use Case
none No auth headers sent Local Collector (no auth needed)
basic Authorization: Basic <base64(token)> Grafana Cloud direct
bearer Authorization: Bearer <token> Generic OTLP endpoints

When using the Collector pattern, set AUTH_MODE=none on the Lambda — the Collector handles backend auth via its own config.

Direct auth modes (basic, bearer) are useful for testing or bypassing the Collector. In the multi-backend pattern, keep AUTH_MODE=none and let the Collector handle backend credentials.

Deployment

Local Development: Docker Run

# 1. Configure credentials
cd integrations/otel-collector
cp .env.example .env
# Edit .env with your backend credentials:
#   GRAFANA_OTLP_ENDPOINT=https://otlp-gateway-prod-ap-northeast-0.grafana.net/otlp
#   GRAFANA_BASIC_AUTH=<base64(instanceId:apiToken)>
#   HONEYCOMB_API_KEY=hcaik_<your-ingest-key>
#   HONEYCOMB_DATASET=fsxn-audit

# 2. Start OTel Collector
docker run -d --name otel-collector \
  -p 4318:4318 -p 13133:13133 \
  -v $(pwd)/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml \
  --env-file .env \
  otel/opentelemetry-collector-contrib:0.152.0

# 3. Verify health
curl -f http://localhost:13133/
# Expected: HTTP 200 — {"status":"Server available", ...}
Enter fullscreen mode Exit fullscreen mode

The health_check extension confirms the Collector process is available; it does not guarantee that each backend exporter is successfully delivering logs. Monitor exporter errors separately using the Collector's internal telemetry metrics if enabled and exposed.

# 4. Send a test payload
bash scripts/generate-otlp-payload.sh --output /tmp/payload.json
curl -X POST http://localhost:4318/v1/logs \
  -H "Content-Type: application/json" \
  -d @/tmp/payload.json
Enter fullscreen mode Exit fullscreen mode

Colima users: docker compose v2 plugin is NOT available in Colima. All scripts in this repo detect this and fall back to docker run. If you see "docker compose: command not found", this is expected behavior.

First Success Path

If you're trying this for the first time, start small:

  1. Run the Collector locally with one backend.
  2. Send one fresh OTLP payload.
  3. Confirm the event appears in that backend.
  4. Add the second exporter.
  5. Only then move to multi-backend or AWS deployment.

This keeps the first validation focused on the producer-to-Collector contract before introducing backend parity and production networking.

AWS Deployment: CloudFormation

aws cloudformation deploy \
  --template-file integrations/otel-collector/template.yaml \
  --stack-name fsxn-otel-integration \
  --parameter-overrides \
    S3AccessPointArn=arn:aws:s3:ap-northeast-1:123456789012:accesspoint/fsxn-audit-ap \
    OtlpEndpoint=http://<your-collector-endpoint>:4318 \
    ApiKeySecretArn=arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:fsxn-otel-key-XXXXXX \
    AuthMode=none \
  --capabilities CAPABILITY_IAM \
  --region ap-northeast-1
Enter fullscreen mode Exit fullscreen mode

This template deploys the Lambda-side OTLP shipper. The Collector endpoint must already be reachable from the Lambda — for example, a local Collector for development, an EC2-hosted Collector, or an ECS/Fargate-based Collector in the same VPC. If the Lambda is in a VPC, ensure security groups allow outbound TCP 4318 to the Collector. See the repository's VPC Deployment Guide and Security Hardening Guide for production Collector deployment.

When the Collector handles auth, set AuthMode=none on the Lambda. The Collector config contains the per-backend credentials via environment variables (sourced from .env or Secrets Manager in production).

Environment Variables

Variable Lambda Collector Description
OTLP_ENDPOINT Collector URL (e.g., http://collector:4318)
AUTH_MODE none / basic / bearer
SERVICE_NAME OTLP service.name attribute
GRAFANA_OTLP_ENDPOINT Grafana Cloud OTLP gateway URL
GRAFANA_BASIC_AUTH base64(instanceId:apiToken)
HONEYCOMB_API_KEY Ingest key (hcaik_...)
HONEYCOMB_DATASET Dataset name
DD_API_KEY Datadog API key
DD_SITE Datadog site (datadoghq.com, datadoghq.eu, ap1.datadoghq.com, etc.)

Verified Results

All backends were tested on 2026-05-18 using otel/opentelemetry-collector-contrib:0.152.0:

Backend Region/Site Status Event Sources Auth Method
Datadog ap1.datadoghq.com ✅ Verified S3 audit + EMS + FPolicy Datadog exporter (DD-API-KEY)
Grafana Cloud ap-northeast-0 ✅ Verified S3 audit + EMS + FPolicy Basic Auth via otlp_http
Honeycomb ✅ Verified S3 audit + EMS + FPolicy x-honeycomb-team via otlp_http
Multi-Backend Grafana + Honeycomb ✅ Verified Simultaneous delivery Both auth methods
Multi-Backend Datadog + Grafana + Honeycomb ✅ Verified Simultaneous 3-way delivery All three exporters

All three backends received the same structured attributes:

  • event.type, user.name, client.address
  • fsxn.operation, fsxn.path, fsxn.result, fsxn.svm
  • cloud.provider=aws, cloud.platform=aws_fsx

OTLP standardizes the producer-to-Collector contract, but backend-specific indexing, query semantics, and retention behavior still need to be validated per destination. OpenTelemetry is not a backend — it defines APIs, protocols, and Collector components for telemetry generation, collection, processing, and export. Storage, visualization, and alerting are handled by the backends themselves. See the Backend Parity Matrix and PoC Checklist for backend-specific validation details.

The Proof: Zero Code Changes

Here's the key evidence. The Lambda handler's SHA-256 hash is identical regardless of which backend receives the logs:

$ shasum -a 256 integrations/otel-collector/lambda/handler.py
# Same hash whether targeting Datadog, Grafana Cloud, or Honeycomb
# The file never changes — only the Collector config does
Enter fullscreen mode Exit fullscreen mode

What changes between backends? Only the OTel Collector config file.

Demonstration: Adding a Backend

Starting state: Grafana Cloud only.

# Before: single backend
service:
  pipelines:
    logs:
      exporters: [otlp_http/grafana]
Enter fullscreen mode Exit fullscreen mode

Adding Honeycomb:

# After: add 5 lines to exporters section + update pipeline
exporters:
  otlp_http/honeycomb:
    endpoint: https://api.honeycomb.io
    headers:
      x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
      x-honeycomb-dataset: ${env:HONEYCOMB_DATASET}

service:
  pipelines:
    logs:
      exporters: [otlp_http/grafana, otlp_http/honeycomb]
Enter fullscreen mode Exit fullscreen mode

Restart the Collector. Done. No Lambda redeployment, no code review, no CI/CD pipeline for the shipper.

Demonstration: Removing a Backend

Dropping Datadog during a migration to Grafana Cloud:

# Remove from exporters list — that's it
service:
  pipelines:
    logs:
      exporters: [otlp_http/grafana]  # removed: datadog
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Timestamp Rejection / Static Payload Gotcha

Datadog documents that logs older than 18 hours are dropped at intake (Datadog Logs API docs). Other backends may also reject or hide events with timestamps outside their accepted windows. In my testing, future timestamps also caused ingestion issues on some backends. When testing with static payloads, always generate fresh timestamps.

Fix: Use the payload generator to create fresh timestamps:

bash scripts/generate-otlp-payload.sh --output /tmp/fresh-payload.json
curl -X POST http://localhost:4318/v1/logs \
  -H "Content-Type: application/json" \
  -d @/tmp/fresh-payload.json
Enter fullscreen mode Exit fullscreen mode

Grafana Cloud Auth Format

The loki exporter is NOT the correct approach for OTLP → Grafana Cloud.

  • loki exporter with Loki push API
  • otlp_http/grafana with OTLP gateway endpoint

The Basic Auth value must be base64(instanceId:apiToken):

# Generate the auth value
echo -n "<your-instance-id>:<your-grafana-cloud-api-token>" | base64
Enter fullscreen mode Exit fullscreen mode

Where the instance ID is your numeric Grafana Cloud instance ID (found in Cloud Portal → OTLP configuration).

Honeycomb Key Types

Honeycomb has two key types. Only ingest keys work for data ingestion:

Key Prefix Type Works for OTLP?
hcaik_ Ingest API key ✅ Yes
hcxik_ Environment key ❌ No

If you see 401 Unauthorized from Honeycomb, check your key prefix.

Colima Docker Compose Compatibility

docker compose v2 plugin is not available in Colima environments. All scripts in this repository detect this automatically and fall back to docker run. This is expected — not an error.

If you need compose-like orchestration on Colima, use the explicit docker run commands shown in the Deployment section.

Common Mistake: loki Exporter vs otlp_http

A frequent misconfiguration when targeting Grafana Cloud:

# ❌ WRONG — loki exporter uses Loki-specific push API
exporters:
  loki:
    endpoint: https://logs-prod-<region>.grafana.net/loki/api/v1/push

# ✅ CORRECT — otlp_http uses the OTLP gateway
exporters:
  otlp_http/grafana:
    endpoint: https://otlp-gateway-prod-<region>.grafana.net/otlp
Enter fullscreen mode Exit fullscreen mode

The OTLP gateway is Grafana Cloud's native OTLP ingestion endpoint. It handles logs, metrics, and traces through a single URL.

Cost Model: How to Think About It

Lambda Cost (OTLP Path vs Direct Send)

In my validation, the OTLP Lambda was simpler and shorter-lived than the vendor-specific direct-send path. Your duration will vary depending on batching, payload size, network path, and backend response time.

Component Direct Send (Part 2) OTLP + Collector
Lambda complexity Vendor formatting + HTTP + retry OTLP POST to nearby Collector
Lambda memory 256MB 256MB
Vendor SDK deps Yes (adds cold start) None
Retry complexity Per-vendor Delegated to Collector

OTel Collector Cost

The Collector introduces a fixed infrastructure cost that is independent of event volume:

Deployment Best For
Docker on local machine Development, testing
Docker on EC2 Spot (t3.small) Low-volume production
ECS Fargate (0.5 vCPU, 1GB) Production (no OS management)
ECS Fargate + NAT Gateway VPC-internal production

When to Use Each Pattern

Scenario Recommendation
Single vendor, low volume Direct Send (Part 2 pattern) — no Collector overhead
Single vendor, high volume Collector (buffering + backpressure benefits)
Multi-vendor evaluation Collector (add/remove exporters freely)
Vendor migration in progress Collector (parallel delivery during cutover)
Compliance: logs in multiple systems Collector (fan-out is a config change)

The Collector has fixed infrastructure costs regardless of volume. As volume increases or vendors multiply, the Collector path becomes more cost-effective because it processes once and fans out. The Collector path centralizes fan-out outside the Lambda. Direct-send can also fan out within one Lambda, but that pushes vendor-specific formatting, retry behavior, and failure isolation back into application code.

Important: Backend ingest/retention costs are not included in these AWS-side estimates. Datadog, Grafana Cloud, and Honeycomb each have their own pricing models that can become the dominant cost at scale.

When to Use This Pattern

Multi-Vendor Evaluation

Want to try Honeycomb for a month alongside your existing Datadog setup? Add one exporter to the Collector config. No Lambda redeployment. No risk to your existing pipeline.

Compliance: Logs in Multiple Systems

Some organizations require audit logs in multiple systems — security team uses Splunk, dev team uses Datadog, compliance team needs a cold archive. The Collector fans out to all simultaneously from a single OTLP stream.

Migration Between Vendors

Moving from Datadog to Grafana Cloud? Run both exporters in parallel during migration. Verify data parity in the new system. Remove the old exporter when satisfied. Zero-downtime vendor migration.

Cost Optimization: Route by Volume

Use the Collector's processor pipeline to route high-volume noisy logs (read operations) to a cheaper backend while keeping security-critical events (deletes, permission changes) on a premium platform with alerting.

What's Next

For production hardening, the repository includes guides covering VPC deployment, health monitoring, persistent buffering, security hardening, and benchmarking. Auto-scaling and Multi-AZ deployment are natural next steps for production Collector operations.

For production and partner-led deployments, the repository includes:

Key Takeaways

  1. OTLP is the stable producer contract. Your Lambda speaks one protocol; the Collector handles backend-specific exporters.
  2. OTel Collector is the routing and processing layer that decouples log producers from observability backends.
  3. Zero Lambda code changes when switching or adding backends — verified with SHA-256 hash comparison.
  4. Multi-backend delivery is a config change, not a code change. Add 5 lines of YAML, restart the Collector.
  5. All three FSx ONTAP event sources work: FSx audit logs via S3 Access Point (Part 2), EMS webhooks (Part 3), and FPolicy file operations (Part 4).
  6. Collector economics improve as volume increases or vendors multiply — fixed Collector cost is amortized across all destinations.
  7. Start with direct send (Part 2) for simplicity. Graduate to the Collector when you need multi-backend, vendor migration, or volume-based routing.

Series Navigation


Questions about the OTel Collector pattern or multi-backend delivery? Drop a comment below.

Previous: Part 4 — FPolicy File Activity Pipeline

GitHub: github.com/Yoshiki0705/fsxn-observability-integrations

Top comments (0)