Skip to content

Configuration

import ai.auralog.Auralog;
import ai.auralog.AuralogConfig;
import java.time.Duration;
Auralog.init(AuralogConfig.builder()
.apiKey("aura_your_api_key")
.environment("production") // default "production"
.endpoint("https://ingest.auralog.ai") // default
.flushInterval(Duration.ofSeconds(5)) // default
.captureErrors(true) // default
.build());
OptionTypeDefaultDescription
apiKeyStringrequiredYour Auralog ingest key. Copy it from the startup modal or create another in project settings.
environmentString"production"e.g. "production", "staging", "dev".
endpointStringhttps://ingest.auralog.aiIngest endpoint override.
flushIntervalDurationDuration.ofSeconds(5)Time between batched flushes. Errors flush immediately regardless.
captureErrorsbooleantrueIf true, uncaught exceptions are auto-reported via Thread.UncaughtExceptionHandler.
globalMetadataSupplier<Map<String, Object>> or Map<String, Object>nullBaseline metadata merged into every log entry — including auralog-slf4j bridge entries and uncaught-exception captures. See Global metadata below.

Available since ai.auralog:auralog-core 0.2.0.

Use globalMetadata to attach session-scoped fields — userId, organisation id, feature-flag snapshot, build SHA — to every log entry without threading them through every call site. The merged metadata flows through direct API calls and entries emitted via the auralog-slf4j bridge and uncaught-exception captures, so attribution is consistent across all three.

If the value never changes for the lifetime of the SDK instance, pass a Map:

Auralog.init(AuralogConfig.builder()
.apiKey("aura_...")
.globalMetadata(Map.of("app", "checkout-service", "region", "us-east-1"))
.build());

This is a convenience overload that wraps the map as () -> map internally; the supplier form below is the load-bearing API.

For values that change at runtime — the canonical case being a per-request ScopedValue or ThreadLocal user — pass a Supplier<Map<String, Object>>. It is invoked at every log emission, so it always reflects current host state:

import java.util.Map;
import java.util.function.Supplier;
Auralog.init(AuralogConfig.builder()
.apiKey("aura_...")
.globalMetadata((Supplier<Map<String, Object>>) () ->
Map.of("userId", CurrentUser.get()))
.build());

Now every direct call, every entry routed through auralog-slf4j, and every uncaught exception carries userId — searchable in the dashboard via userId:abc and visible to your AI provider during analysis.

When a per-call metadata argument is also provided, the two are shallow-merged with per-call winning on collision:

// globalMetadata: () -> Map.of("userId", "u_42", "region", "us")
auralog.info("impersonating session", Map.of("userId", "u_99"));
// final metadata: {userId=u_99, region=us}

This lets a specific log line legitimately reference a different user (impersonation, admin actions) without mutating global state.

The SDK never crashes the host. If the supplier:

  • throws — the entry ships without globalMetadata (per-call metadata is preserved). A single warning fires per Logger instance via System.Logger at WARNING (logger name ai.auralog.internal); subsequent failures of the same kind are silent.
  • returns a CompletionStage / CompletableFuture — same. Async suppliers are not awaited; cache async state in something synchronously accessible (ScopedValue, ThreadLocal).
  • returns a value the JSON encoder cannot serialize (circular refs, opaque types) — same. The entry still ships with just per-call metadata.

SLF4J MDC is not auto-merged into globalMetadata. Today the bridge installs a NOPMDCAdapter so MDC is a no-op, but even when MDC populates we keep it separate from globalMetadata to avoid mental-model overlap. Auto-MDC-merge is a candidate for a future opt-in flag if there’s demand.

The supplier runs on every log emission. Keep it O(1) — read from a ScopedValue / ThreadLocal / cached object, not a database or remote call.

AuralogConfig is immutable; build with AuralogConfig.builder():

AuralogConfig config = AuralogConfig.builder()
.apiKey("k")
.environment("staging")
.build();
Auralog.init(config);

apiKey is the only required field. Everything else has sensible defaults.

Calling Auralog.init(...) again replaces the previous configuration and flushes the prior transport. Useful for rotating API keys without restarting the JVM.

Auralog.init(AuralogConfig.builder()
.apiKey(System.getenv("AURALOG_API_KEY"))
.environment(System.getenv().getOrDefault("APP_ENV", "dev"))
.build());