MCPcopy Index your code
hub / github.com/Divkix/Logwell

github.com/Divkix/Logwell @v1.1.3

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.1.3 ↗ · + Follow
1,064 symbols 4,254 edges 246 files 748 documented · 70%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Logwell - Self-hosted logging for high-performance apps

Logwell is a self-hosted logging platform with real-time streaming, full-text search, and OTLP-compatible ingestion. Deploy in minutes, own your data.

Alpha Software — Expect breaking changes. Not recommended for production workloads.

License: MIT GitHub stars Build Status npm version JSR PyPI version Go Reference TypeScript Python Go Bun

FeaturesQuick StartUsageDeployContributingLicense


What is Logwell?

Logwell is a lightweight, self-hosted log aggregation platform for developers who want structured logging without the complexity of ELK or the costs of cloud services.

Use Logwell when you need:

  • A simple logging backend for your side project or startup
  • Full-text search across logs without managing Elasticsearch
  • Real-time log streaming during development and debugging
  • Complete data ownership with no vendor lock-in

Logwell is NOT for:

  • High-volume production systems (10k+ logs/second) — use Loki or Clickhouse
  • Teams needing RBAC, audit trails, or compliance features — use a managed service
  • Distributed tracing or metrics — Logwell is logs-only

Features

  • OTLP-native ingestion — Standard OpenTelemetry protocol, no proprietary SDKs required
  • PostgreSQL backend — Full-text search via tsvector, no separate search cluster needed
  • Real-time streaming — SSE-powered live log tailing with batching
  • Incident intelligence — Error/fatal fingerprinting with incident timeline and correlation hints
  • Project isolation — Per-project API keys with separate log streams
  • Zero telemetry — No phone-home, no tracking, fully air-gapped deployments supported
  • Clean UI — Minimal interface with dark mode and log level color coding

Preview

Real-time log streaming demo

Log Viewer Real-time log viewer with level filtering Quick Start Quick Start with pre-filled API key
Project Settings API key management and code snippets Statistics Log level distribution analytics

Why Logwell?

vs Logwell advantage
Loki/Grafana Built-in UI, no LogQL to learn, just PostgreSQL
ELK Lightweight PostgreSQL backend, not Elasticsearch
Datadog/etc Self-hosted, no per-GB pricing, own your data

Tech Stack

Layer Technology
Framework SvelteKit
Database PostgreSQL
ORM Drizzle
Auth better-auth
UI shadcn-svelte + Tailwind CSS v4
Real-time Server-Sent Events
Runtime Bun

Prerequisites

Quick Start

# Clone the repository
git clone https://github.com/divkix/logwell.git
cd logwell

# Install dependencies
bun install

# Set up environment
cp .env.example .env
# Edit .env with your values (see Environment Variables below)

# Start PostgreSQL
docker compose up -d

# Run database migrations
bun run db:migrate

# Create admin user
bun run db:seed

# Start development server
bun run dev

Open http://localhost:5173 and sign in with:

  • Username: admin (or your ADMIN_USERNAME from .env)
  • Password: Your ADMIN_PASSWORD from .env

Note: Development runs on port 5173 (Vite). Production builds run on port 3000.

Environment Variables

Create a .env file with the following:

# Database connection
DATABASE_URL="postgres://root:mysecretpassword@localhost:5432/local"

# Authentication secret (minimum 32 characters)
BETTER_AUTH_SECRET="your-32-character-secret-key-here"

# Admin user password (minimum 8 characters)
ADMIN_PASSWORD="your-admin-password"

# Admin username (optional, defaults to "admin")
# ADMIN_USERNAME="admin"

# Production URL (required for auth behind reverse proxies)
ORIGIN="https://your-domain.com"

# Log retention (optional, defaults shown)
# LOG_RETENTION_DAYS="30"        # 0 = never auto-delete
# LOG_CLEANUP_INTERVAL_MS="3600000"  # Cleanup job interval (1 hour)
# INCIDENT_AUTO_RESOLVE_MINUTES="30" # Incident resolves after N quiet minutes

# Rate limiting (optional, defaults shown)
# RATE_LIMIT_INGEST_RPM="600"    # Max ingest requests per minute per API key
# RATE_LIMIT_LOGIN_RPM="10"      # Max login attempts per minute per IP

Generate a secure secret:

openssl rand -base64 32

Usage

Create a Project

  1. Sign in to the dashboard
  2. Click New Project
  3. Enter a project name
  4. Copy the generated API key (lw_...)

Send Logs

Logwell provides two ingestion APIs:

API Endpoint Best For
Simple API POST /v1/ingest Quick integration, any HTTP client
OTLP API POST /v1/logs OpenTelemetry SDKs, rich metadata

Simple API (Recommended for quick start)

The simple API accepts flat JSON with minimal boilerplate:

curl -X POST http://localhost:5173/v1/ingest \
  -H "Authorization: Bearer lw_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"level": "info", "message": "User signed in"}'

Batch multiple logs:

curl -X POST http://localhost:5173/v1/ingest \
  -H "Authorization: Bearer lw_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {"level": "info", "message": "Request started"},
    {"level": "error", "message": "Database timeout", "metadata": {"query": "SELECT..."}}
  ]'

Available fields:

Field Required Type Description
level Yes debug | info | warn | error | fatal Log severity
message Yes string Log message
timestamp No ISO8601 string Defaults to current time
service No string Service name for filtering
metadata No object Additional structured data

Node.js (no SDK needed)

await fetch("http://localhost:5173/v1/ingest", {
  method: "POST",
  headers: {
    Authorization: "Bearer lw_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ level: "info", message: "Hello from Node.js" }),
});

Python (no SDK needed)

import requests

requests.post('http://localhost:5173/v1/ingest',
    headers={'Authorization': 'Bearer lw_YOUR_API_KEY'},
    json={'level': 'info', 'message': 'Hello from Python'})

Go (no SDK needed)

body := []byte(`{"level": "info", "message": "Hello from Go"}`)
req, _ := http.NewRequest("POST", "http://localhost:5173/v1/ingest", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer lw_YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)

TypeScript/JavaScript SDK

For Node.js, browsers, and edge runtimes (Cloudflare Workers, etc.):

npm install logwell
import { Logwell } from "logwell";

const logger = new Logwell({
  apiKey: "lw_YOUR_API_KEY",
  endpoint: "http://localhost:5173",
});

// Log at different levels
logger.info("User signed in", { userId: "123" });
logger.error("Database failed", { host: "db.local" });

// Flush before shutdown
await logger.shutdown();

Features: Zero dependencies, automatic batching, retry with backoff, TypeScript-first, opt-in source location capture.

Deno users: Install from JSR with deno add jsr:@divkix/logwell and import from @divkix/logwell

Full SDK documentation →


Python SDK

For Python applications with automatic batching and retries:

pip install logwell
import asyncio
from logwell import Logwell

client = Logwell({
    'api_key': 'lw_YOUR_API_KEY',
    'endpoint': 'http://localhost:5173',
    'service': 'my-app',
})

# Log at different levels
client.info('User signed in', {'user_id': '123'})
client.error('Database failed', {'host': 'db.local'})

# Flush before shutdown
asyncio.run(client.shutdown())

Features: Async batching, automatic retries with backoff, child loggers, typed errors, source location capture.

Full SDK documentation →


Go SDK

For Go applications with zero external dependencies:

go get github.com/Divkix/Logwell/sdks/go
package main

import (
    "context"
    "log"

    "github.com/Divkix/Logwell/sdks/go/logwell"
)

func main() {
    client, err := logwell.New(
        "http://localhost:5173",
        "lw_YOUR_API_KEY",
        logwell.WithService("my-app"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Log at different levels
    client.Info("User signed in", logwell.M{"userId": "123"})
    client.Error("Database failed", logwell.M{"host": "db.local"})

    // Flush before shutdown
    if err := client.Shutdown(context.Background()); err != nil {
        log.Printf("Shutdown error: %v", err)
    }
}

Features: Zero dependencies, automatic batching, retry with backoff, child loggers, source location capture.

Full SDK documentation →


OTLP API (For OpenTelemetry Users)

For applications already using OpenTelemetry, point your OTLP log exporter to POST /v1/logs with your API key in the Authorization header.

Node.js / TypeScript

npm install @opentelemetry/exporter-logs-otlp-http @opentelemetry/sdk-logs
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
import { LoggerProvider, BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";

const exporter = new OTLPLogExporter({
  url: "http://localhost:5173/v1/logs",
  headers: { Authorization: "Bearer lw_YOUR_API_KEY" },
});

const loggerProvider = new LoggerProvider();
loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(exporter));

Python

pip install opentelemetry-exporter-otlp-proto-http
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor

exporter = OTLPLogExporter(
    endpoint="http://localhost:5173/v1/logs",
    headers={"Authorization": "Bearer lw_YOUR_API_KEY"},
)

logger_provider = LoggerProvider()
logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))

Go

go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp

```go import ( "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" "go.opentelemetry.io/otel/sdk/log" )

exporter, _ := otlploghttp.New(ctx, otlploghttp.WithEndpointURL("http://localhost:5173/v1/logs"), otlploghttp.WithHeaders(map[string]string{ "Authorization": "Bearer lw_YOUR_API_KEY",

Extension points exported contracts — how you extend this code

Option (FuncType)
Option is a functional option for configuring the client.
sdks/go/logwell/config.go
HealthResponse (Interface)
* Health check response type
src/routes/api/health/+server.ts
ShortcutDefinition (Interface)
* Shortcut definition for the help modal.
src/lib/utils/keyboard.ts
SourceLocation (Interface)
(no doc)
sdks/typescript/src/source-location.ts
Locals (Interface)
(no doc)
src/app.d.ts
ChildOption (FuncType)
ChildOption configures a child logger created via Client.Child().
sdks/go/logwell/client.go
CacheEntry (Interface)
* API Key cache entry with project ID, key hash, and expiration time
src/lib/server/utils/api-key.ts
ChildLoggerOptions (Interface)
(no doc)
sdks/typescript/src/client.ts

Core symbols most depended-on inside this repo

seedProject
called by 225
tests/fixtures/db.ts
GET
called by 115
src/routes/api/health/+server.ts
seedLogs
called by 94
tests/fixtures/db.ts
add
called by 67
sdks/python/src/logwell/queue.py
POST
called by 67
src/routes/v1/logs/+server.ts
seedLog
called by 67
tests/fixtures/db.ts
info
called by 63
sdks/python/src/logwell/client.py
validate_config
called by 59
sdks/python/src/logwell/config.py

Shape

Function 489
Method 432
Class 86
Interface 43
Struct 9
TypeAlias 3
FuncType 2

Languages

Python46%
TypeScript39%
Go14%

Modules by API surface

sdks/python/tests/unit/test_config.py90 symbols
sdks/python/tests/unit/test_client.py85 symbols
sdks/python/tests/unit/test_queue.py68 symbols
sdks/python/tests/unit/test_errors.py64 symbols
sdks/python/tests/unit/test_source_location.py52 symbols
sdks/python/tests/conftest.py42 symbols
sdks/python/tests/integration/test_e2e.py33 symbols
sdks/go/logwell/client_test.go25 symbols
src/lib/server/utils/otlp.ts23 symbols
sdks/go/logwell/queue_test.go21 symbols
sdks/go/logwell/config.go20 symbols
sdks/go/logwell/client.go20 symbols

Datastores touched

(mysql)Database · 1 repos
buildDatabase · 1 repos
dbDatabase · 1 repos
localDatabase · 1 repos
mydbDatabase · 1 repos

For agents

$ claude mcp add Logwell \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact