Skip to content

guibranco/logstream-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

37 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

logstream-server

πŸ“‘πŸͺ΅ Real-time log ingestion and streaming service built with PHP 8.3 + ReactPHP + Ratchet


Architecture

[ Your apps ]  ──POST /api/logs──▢  [ HTTP server :8081 ]
                                            β”‚
                                       saves to storage
                                       (MariaDB / JSONL)
                                            β”‚
                                       broadcasts via
                                            β–Ό
                                  [ WS server :8080 ]  ──▢  [ React UI ]

Quick start

# 1. Install dependencies
composer install

# 2. Configure
cp .env.example .env
# Edit .env – set API_SECRET, choose STORAGE_TYPE, etc.

# 3a. MariaDB (optional)
mysql -u root -p < migrations/001_logs.sql

# 3b. File storage – nothing to do; directories are auto-created.

# 4. Run
php bin/server.php

API Reference

All requests to write endpoints must include:

Authorization: Bearer <API_SECRET>

POST /api/logs β€” Ingest logs

Batch payload (recommended):

{
  "app_key":  "billing-api",
  "app_id":   "production",
  "batch_id": "550e8400-e29b-41d4-a716-446655440000",
  "logs": [
    {
      "trace_id":  "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "level":     "error",
      "category":  "payments",
      "message":   "Charge failed for invoice #1234",
      "context":   { "invoice_id": 1234, "code": "card_declined" },
      "timestamp": "2025-01-15T14:22:00.000Z"
    }
  ]
}

User-Agent header is captured as the application identifier:

User-Agent: BillingService/2.1.0 (PHP 8.3)

Single-entry shorthand:

{
  "app_key":  "billing-api",
  "app_id":   "production",
  "level":    "info",
  "category": "startup",
  "message":  "Service started"
}

Response (201):

{
  "saved":   1,
  "entries": [ { ...LogEntry } ],
  "errors":  null
}

GET /api/logs β€” Search

Param Type Description
app_key string Exact match
app_id string Exact match
user_agent string Partial match
level string debug|info|notice|warning|error|critical
category string Partial match
trace_id string Exact match
batch_id string Exact match
date_from string ISO 8601 timestamp (inclusive)
date_to string ISO 8601 timestamp (inclusive)
search string Substring match on message
limit int Max entries returned (default 100, max 1000)
offset int Pagination offset (default 0)

Response (200):

{
  "total":   42,
  "limit":   100,
  "offset":  0,
  "entries": [ { ...LogEntry } ]
}

GET /api/logs/:id

Fetch a single entry by internal id or trace_id.


GET /api/health

{ "status": "ok", "time": "...", "ws_connections": 2 }

WebSocket – ws://host:8080

Connect from the UI to receive a live stream of every ingested log.

On connect the server sends:

{ "type": "connected", "connections": 1 }

Every new log entry is broadcast as:

{
  "type": "log",
  "data": {
    "id":         "01HZXYZ...",
    "trace_id":   "uuid-v4",
    "batch_id":   "uuid-v4 | null",
    "app_key":    "billing-api",
    "app_id":     "production",
    "user_agent": "BillingService/2.1.0",
    "level":      "error",
    "category":   "payments",
    "message":    "Charge failed",
    "context":    { ... },
    "timestamp":  "2025-01-15T14:22:00.000Z",
    "created_at": "2025-01-15T14:22:00.012Z"
  }
}

Client β†’ server messages:

{ "type": "ping" }   β†’   { "type": "pong" }
{ "type": "stats" }  β†’   { "type": "stats", "data": { "connections": 2 } }

LogEntry fields

Field Type Notes
id string (ULID) Time-sortable, generated by server
trace_id string (UUID) Provide your own or let server generate
batch_id string (UUID)? Groups entries in the same request
app_key string ≀100 Required. Application slug
app_id string ≀100 Required. Instance / environment
user_agent string ≀255? Application name & version
level enum debug / info / notice / warning / error / critical
category string ≀100 Free-form grouping tag
message string Human-readable description
context object? Arbitrary structured data
timestamp ISO 8601 When the event occurred
created_at ISO 8601 When the server persisted it

About

πŸ“‘πŸͺ΅ Real-time log ingestion and streaming service built with PHP 8.3 and ReactPHP

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors