LogFlux Java SDK

Java Logo

The official Java SDK for LogFlux. Send logs, metrics, traces, events, and audit entries directly to the LogFlux cloud with end-to-end encryption from Java and Kotlin applications. The server never sees your plaintext data.

GitHub Repository ยท Release Notes

Key Features

  • End-to-end encryption – AES-256-GCM with RSA key exchange
  • 7 entry types – Log, Metric, Trace, Event, Audit, Telemetry, TelemetryManaged
  • Multipart binary transport – 33% less overhead than JSON + base64
  • Async by default – Background daemon threads with non-blocking queue
  • Breadcrumbs – Automatic trail of recent events attached to error captures
  • Distributed tracing – Spans, child spans, trace header propagation
  • Scopes – Per-request context isolation
  • Failsafe – SDK errors never crash your application
  • Zero external dependencies – javax.crypto, java.net.http, java.util.zip

Installation

Gradle

1
implementation 'io.logflux:logflux-java-sdk:3.0.1'

Maven

1
2
3
4
5
<dependency>
    <groupId>io.logflux</groupId>
    <artifactId>logflux-java-sdk</artifactId>
    <version>3.0.1</version>
</dependency>

Quick Start

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import io.logflux.sdk.LogFlux;
import io.logflux.sdk.Options;

public class Main {
    public static void main(String[] args) {
        LogFlux.init(Options.builder("eu-lf_your_api_key")
            .source("my-service")
            .environment("production")
            .release("1.2.3")
            .build());

        LogFlux.info("server started");

        // Before process exit
        LogFlux.flush(2000);
        LogFlux.close();
    }
}

Entry Types

Log (Type 1)

Standard application logs with 8 severity levels.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
LogFlux.debug("cache miss for key users:123");
LogFlux.info("request processed");
LogFlux.warn("deprecated API called");
LogFlux.error("database connection failed");
LogFlux.critical("out of memory");

// With attributes
LogFlux.log(LogLevel.ERROR, "query timeout", Map.of(
    "db.host", "primary.db.internal",
    "duration_ms", "5023"
));

Metric (Type 2)

Counters, gauges, and distributions.

1
2
3
4
5
6
7
8
LogFlux.counter("http.requests.total", 1, Map.of(
    "method", "GET",
    "status", "200"
));

LogFlux.gauge("system.cpu.usage", 85.2, Map.of(
    "host", "web-01"
));

Event (Type 4)

Discrete application events.

1
2
3
4
LogFlux.event("user.signup", Map.of(
    "user_id", "usr_987",
    "plan", "starter"
));

Audit (Type 5)

Immutable audit trail with Object Lock storage (365-day retention).

1
2
3
LogFlux.audit("record.deleted", "usr_456", "invoice", "inv_789", Map.of(
    "reason", "customer_request"
));

Trace (Type 3)

Distributed tracing with span helpers.

1
2
3
4
5
6
7
Span span = LogFlux.startSpan("http.server", "GET /api/users");

Span dbSpan = span.startChild("db.query", "SELECT * FROM users");
// ... query ...
dbSpan.end();

span.end();

Telemetry (Types 6 and 7)

Device and sensor data. Type 6 is end-to-end encrypted, type 7 is server-side encrypted.

Error Capture

Capture Java exceptions with automatic stack traces and breadcrumb trail.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
try {
    database.query(sql);
} catch (Exception e) {
    LogFlux.captureError(e);

    // With extra context
    LogFlux.captureError(e, Map.of(
        "sql", sql,
        "db.host", "primary"
    ));
}

Throwable chain unwrapping: if the exception has a cause chain, all causes are captured.

Breadcrumbs record a trail of events leading up to an error. They are automatically added for log and event calls, and attached to captureError.

1
2
3
4
5
6
7
8
LogFlux.info("loading config");          // auto breadcrumb
LogFlux.event("user.login", null);       // auto breadcrumb

LogFlux.addBreadcrumb("http", "GET /api/users", Map.of(
    "status", "200"
));

LogFlux.captureError(exception);  // includes breadcrumb trail

Scopes

Per-request context isolation. Attributes set on a scope are merged into every entry.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
LogFlux.withScope(scope -> {
    scope.setUser("usr_456");
    scope.setRequest("GET", "/api/users", "req_abc123");
    scope.setAttribute("tenant", "acme-corp");

    scope.info("processing request");

    if (error != null) {
        scope.captureError(error);
    }
});

Trace Context Propagation

Propagate trace context across services via HTTP headers.

1
2
3
4
5
6
7
8
// Client: inject trace header
Span span = LogFlux.startSpan("http.client", "GET /api");
Map<String, String> headers = span.injectHeaders();

// Server: continue from incoming headers
Span span = LogFlux.continueFromHeaders(request.getHeaders(), "http.server", "GET /api");
// ... handle request ...
span.end();

Framework Integration

Spring Boot

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import io.logflux.sdk.LogFlux;
import io.logflux.sdk.Options;
import io.logflux.sdk.Span;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.*;

@Component
public class LogFluxFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        Span span = LogFlux.startSpan("http.server",
            request.getMethod() + " " + request.getRequestURI());
        span.setAttribute("http.method", request.getMethod());

        try {
            chain.doFilter(req, res);
            HttpServletResponse response = (HttpServletResponse) res;
            span.setAttribute("http.status_code", String.valueOf(response.getStatus()));
        } catch (Exception e) {
            span.setError(e);
            throw e;
        } finally {
            span.end();
        }
    }
}

Android

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import io.logflux.sdk.LogFlux;
import io.logflux.sdk.Options;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        LogFlux.init(Options.builder("eu-lf_your_api_key")
            .source("my-android-app")
            .environment("production")
            .release(BuildConfig.VERSION_NAME)
            .build());

        // Capture uncaught exceptions
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            LogFlux.captureError(throwable);
            LogFlux.flush(2000);
        });
    }
}

Configuration

Options (Builder Pattern)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Options options = Options.builder("eu-lf_your_api_key")
    .source("my-service")
    .environment("production")
    .release("1.2.3")
    .queueSize(1000)
    .batchSize(100)
    .flushInterval(5000)
    .workerCount(2)
    .maxRetries(3)
    .sampleRate(1.0)
    .maxBreadcrumbs(100)
    .failsafe(true)
    .enableCompression(true)
    .build();

Environment Variables

1
LogFlux.initFromEnv("my-node");

Reads LOGFLUX_API_KEY, LOGFLUX_ENVIRONMENT, LOGFLUX_NODE, LOGFLUX_QUEUE_SIZE, LOGFLUX_BATCH_SIZE, LOGFLUX_KEY_PERSISTENCE, LOGFLUX_KEY_PERSISTENCE_PATH, LOGFLUX_KEY_ROTATION_DAYS, etc.

Key Persistence

The SDK persists AES encryption keys to disk by default, reusing them across restarts instead of performing a new handshake each time. This reduces key proliferation in the database and speeds up initialization.

OptionTypeDefaultDescription
.keyPersistence(boolean)booleantrueEnable/disable key persistence
.keyPersistencePath(String)String~/.logflux/sessions/Custom directory for session files
.keyRotationDays(long)long0 (never)Rotate key after N days

Session files are stored at ~/.logflux/sessions/<hash>.json with 0600 permissions. If the cached key is rejected by the server (401/403), the SDK automatically re-handshakes and saves the new key.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Disable persistence (for ephemeral containers)
LogFlux.init(Options.builder("eu-lf_your_key")
    .keyPersistence(false)
    .build());

// Custom path and 30-day rotation
LogFlux.init(Options.builder("eu-lf_your_key")
    .keyPersistencePath("/var/lib/myapp/logflux/")
    .keyRotationDays(30)
    .build());

On Android, keys are stored in the Android Keystore instead of the filesystem. No additional configuration is required.

BeforeSend Hooks

Filter or modify entries before they are sent. Return null to drop.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Options options = Options.builder("eu-lf_...")
    .beforeSendLog(log -> {
        if ((int) log.get("level") == 8) return null;  // drop debug
        return log;
    })
    .beforeSendAudit(audit -> {
        ((Map<String, String>) audit.get("attributes")).remove("ip");
        return audit;
    })
    .build();

Sampling

1
Options.builder("...").sampleRate(0.1).build();  // send 10%

Audit entries (type 5) are never sampled.

Security

  • Zero-knowledge: All payloads encrypted client-side with AES-256-GCM
  • RSA key exchange: AES keys negotiated via RSA-2048 OAEP handshake
  • Key zeroing: AES keys cleared from memory on close()
  • Bounded reads: All HTTP responses size-limited
  • Failsafe: SDK errors never crash the host application

Requirements

  • Java 11 or later
  • LogFlux account with API key

License

Elastic License 2.0 (ELv2) – free for all use except offering as a hosted or managed service to third parties.

Support

Disclaimer

The Java logo and trademarks are the property of Oracle Corporation. LogFlux is not affiliated with, endorsed by, or sponsored by Oracle Corporation. The Java logo is used solely for identification purposes to indicate compatibility and integration capabilities.