Skip to content

axonops/audit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

503 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audit

audit

Structured, Schema-Enforced Audit Logging for Go Services

CI Go Reference Go Report Card License Status

🚀 Quick Start | ✨ Features | 📚 Examples | 📖 API Reference


🔍 Overview

audit is an audit logging library for Go. Audit logging is different from application logging — application logs record technical details for debugging (log/slog, zap), while audit logs record who did what, when, and to which resource for compliance, forensics, and accountability. If your application handles user data, authentication, or financial transactions, regulations like SOX, HIPAA, and GDPR require structured audit trails that application loggers don't enforce.

The library splits audit configuration into two layers:

  • Compile-time (taxonomy): Your event schema — which event types exist, which fields are required, what's optional — is defined in a YAML file and embedded into your binary with go:embed. A code generator (audit-gen) produces typed Go builders from this schema, so invalid event names and missing required fields are caught by the compiler, not at runtime. The taxonomy is your audit contract — it ships with the binary and cannot be changed without recompiling.

  • Runtime (outputs): Where events go — files, syslog, webhooks — is configured in a separate YAML file loaded at startup. Output destinations, routing filters, formatters, and sensitivity label exclusions can all change per environment without rebuilding.

The library validates events against the compiled taxonomy, delivers them asynchronously to multiple outputs simultaneously, and supports both JSON and CEF (Common Event Format) for SIEM integration.


✨ Key Features

Feature Description Docs
📋 Taxonomy Validation Define event schemas in YAML; every event validated at runtime Learn more
⚙️ Code Generation audit-gen generates typed builders; typos become compile errors Learn more
🛡️ CEF Format Common Event Format for SIEM platforms (Splunk, ArcSight, QRadar) Learn more
📄 JSON Format Line-delimited JSON with deterministic field order Learn more
📡 5 Output Types File (rotation), syslog (RFC 5424), webhook (NDJSON), Loki (stream labels), stdout — fan-out to all simultaneously Learn more
🔀 Event Routing Route events by category or severity to specific outputs Learn more
🔒 Sensitivity Labels Classify fields as PII/financial; strip per-output for compliance Learn more
Async Delivery Sub-microsecond enqueue; background drain goroutine Learn more
🌐 HTTP Middleware Automatically captures HTTP request fields for audit logging Learn more
📊 Metrics & Monitoring Track dropped events, delivery errors, and output health Learn more
📝 YAML Configuration Configure outputs in YAML with environment variable substitution Learn more
🔐 HMAC Integrity Per-output tamper detection with NIST-approved algorithms Learn more
🧪 Testing Support In-memory recorder with same validation as production Learn more

❓ Why Audit Logging?

Audit logging is not application logging. They serve fundamentally different purposes:

🔧 Application Logging 📋 Audit Logging
Purpose Debugging, troubleshooting, observability Compliance, forensics, accountability
Audience Developers, SREs Security teams, auditors, legal
Guarantees Best-effort — missing a log line is fine Schema-enforced — missing a field is a compliance gap
Retention Days to weeks Months to years (regulatory requirements)
Content Technical details (errors, stack traces) Who did what, when, to which resource, and why
Destinations Log aggregator (OpenSearch, Datadog, Loki) SIEM (Splunk, ArcSight, QRadar), compliance archives

If your application handles user data, financial transactions, authentication, or access control, regulations like SOX, HIPAA, GDPR, and PCI-DSS require audit trails. Application loggers (log/slog, zap, zerolog) do not enforce the structure, completeness, or delivery guarantees that compliance demands.


💡 Why audit?

No existing Go library provides schema-enforced audit logging with multi-output fan-out and SIEM-native format support:

  • 📋 Schema enforcement — every event validated against your taxonomy; missing required fields are rejected, not silently dropped
  • 🛡️ SIEM-native outputCEF format understood by Splunk, ArcSight, QRadar out of the box, alongside JSON for log aggregators
  • 📡 Multi-output fan-out — send events to files, syslog, webhooks, Loki, and stdout simultaneously, each with its own formatter and filters
  • 🔒 Sensitive field strippingclassify fields as PII or financial; strip them per-output for GDPR/PCI compliance
  • Non-blocking — sub-microsecond AuditEvent() calls; async delivery via a background drain goroutine with completeness monitoring
  • 🔌 No vendor lock-inpluggable metrics interface; no Prometheus, OpenTelemetry, or logging framework dependency in core

🚀 Quick Start

The library uses a YAML-first workflow: define your events in a taxonomy file, configure outputs in another, and generate type-safe Go code.

1️⃣ Define your taxonomy (taxonomy.yaml) - This is your source code.

version: 1

categories:
  write:
    severity: 3
    events:
      - user_create
  security:
    severity: 8
    events:
      - auth_failure

events:
  user_create:
    description: "A new user account was created"
    fields:
      outcome:  { required: true }
      actor_id: { required: true }

  auth_failure:
    description: "An authentication attempt failed"
    fields:
      outcome:  { required: true }
      actor_id: { required: true }

💡 Fields like target_id, source_ip, and reason are reserved standard fields — always available on every event without declaration. Use .SetTargetID(), .SetSourceIP(), etc. on any builder.

2️⃣ Configure outputs (outputs.yaml) - This is your config.

version: 1
app_name: my-service
host: "${HOSTNAME:-localhost}"

outputs:
  console:
    type: stdout

  siem_log:
    type: file
    file:
      path: "./audit-cef.log"
    formatter:
      type: cef
      vendor: "MyCompany"
      product: "MyApp"
      version: "1.0"

3️⃣ Generate type-safe code

go run github.com/axonops/audit/cmd/audit-gen \
  -input taxonomy.yaml \
  -output audit_generated.go \
  -package main

💡 go run fetches the tool automatically — no separate install needed.

4️⃣ Use the generated builders

// Required fields are constructor parameters — typos are compile errors
err := logger.AuditEvent(
    NewUserCreateEvent("alice", "success").
        SetTargetID("user-42"),
)

📚 For the complete runnable application (taxonomy loading, output configuration, logger creation), see examples/02-code-generation.

Output

📄 JSON (default formatter):

{"timestamp":"...","event_type":"user_create","severity":3,"app_name":"my-service","host":"prod-01","timezone":"UTC","pid":12345,"actor_id":"alice","outcome":"success","target_id":"user-42","event_category":"write"}

🛡️ CEF (SIEM formatter):

CEF:0|MyCompany|MyApp|1.0|user_create|A new user account was created|3|rt=... act=user_create deviceProcessName=my-service dvchost=prod-01 dvcpid=12345 suser=alice outcome=success cat=write

app_name, host, and pid are framework fields — set once in your outputs.yaml and automatically included in every event. The host, timezone, and pid values reflect your system — they will differ from the example above. app_name is set in outputs.yaml and stays constant across deployments. SIEMs use the CEF extension keys (deviceProcessName, dvchost, dvcpid) for automatic host-level correlation.


📦 Installation

Requires Go 1.26+.

go get github.com/axonops/audit             # core: logger, taxonomy, validation, formatters, stdout output
go get github.com/axonops/audit/file         # file output with rotation
go get github.com/axonops/audit/syslog       # RFC 5424 syslog (TCP/UDP/TLS/mTLS)
go get github.com/axonops/audit/webhook      # batched HTTP webhook with SSRF protection
go get github.com/axonops/audit/loki         # Grafana Loki with stream labels and gzip
go get github.com/axonops/audit/outputconfig # YAML-based output configuration

💡 The core module includes StdoutOutput (no additional dependency) and the audittest package for testing.


🏗️ Module Structure

Module Description
github.com/axonops/audit Core: Logger, taxonomy validation, JSON + CEF formatters, HTTP middleware, stdout output, fan-out, routing, audittest
github.com/axonops/audit/file File output with size-based rotation and gzip compression
github.com/axonops/audit/syslog RFC 5424 syslog output (TCP/UDP/TLS/mTLS)
github.com/axonops/audit/webhook Batched HTTP webhook with retry and SSRF protection
github.com/axonops/audit/loki Grafana Loki output with stream labels, gzip, multi-tenancy
github.com/axonops/audit/outputconfig YAML-based output configuration with env var substitution
github.com/axonops/audit/outputs Convenience: single blank import registers all output factories
github.com/axonops/audit/secrets Secret provider interface for ref+ URI resolution in YAML config
github.com/axonops/audit/secrets/openbao OpenBao KV v2 secret provider
github.com/axonops/audit/secrets/vault HashiCorp Vault KV v2 secret provider
github.com/axonops/audit/cmd/audit-gen Code generator: YAML taxonomy to typed Go builders

Outputs are isolated in separate modules so the core library carries minimal third-party dependencies. Import only the outputs you use — or import _ "github.com/axonops/audit/outputs" to register all of them.


🧪 Testing

The audittest package provides an in-memory recorder for testing audit events:

func TestUserCreation(t *testing.T) {
    logger, events, _ := audittest.NewLoggerQuick(t, "user_create")

    // Exercise the code under test...
    err := logger.AuditEvent(audit.NewEventKV("user_create",
        "outcome", "success", "actor_id", "alice"))
    require.NoError(t, err)

    // Assert immediately — NewLoggerQuick uses synchronous delivery.
    assert.Equal(t, 1, events.Count())
    assert.Equal(t, "alice", events.Events()[0].StringField("actor_id"))
}

See Example 4 and Testing docs for more.


📚 Documentation

Resource Description
📖 Progressive Examples 17 examples from "hello world" to a complete inventory demo — every output type, TLS policy, routing, formatters, testing, and buffering
📘 API Reference pkg.go.dev documentation
🏗️ Architecture Pipeline design, module boundaries, thread safety
🤝 Contributing Development setup, PR process, code standards
📝 Changelog Release history and breaking changes
Error Reference Every error explained with recovery guidance
🔧 Troubleshooting Common problems and how to fix them
🔒 Security Policy Vulnerability reporting
Benchmarks Performance baseline and methodology

⚠️ Status

This library is pre-release (v0.x). The API may change between minor versions until v1.0.0. Pin your dependency version.


🙏 Acknowledgements

audit builds on excellent open-source projects. See ACKNOWLEDGEMENTS.md for full attribution and license details.


📄 License

Apache License 2.0 — Copyright 2026 AxonOps Limited.


Made with ❤️ by AxonOps

About

Structured, compile time schema-enforced audit logging for Go services. Taxonomy-driven validation, type-safe code generation, multi-output fan-out (file, syslog, webhook and more), CEF + JSON formatters, HMAC integrity checks, per-output event routing, sensitivity labels, and async delivery.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages