LogNest collects, stores, and visualizes your application logs locally in real-time. One dependency install — your logs start flowing instantly.
localhost:9000.tail -f with auto-scroll.docker logs -f across 5 terminals. Filter by service name, correlate errors across services, spot cascading failures in seconds.<dependency>
<groupId>com.lognest</groupId>
<artifactId>lognest-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
lognest.service=payment-service # Optional — these are the defaults: # lognest.url=http://localhost:9000/logs # lognest.level=DEBUG # lognest.enabled=true
// Your existing code — zero changes needed
log.info("Payment processed", Map.of("orderId", id));
log.error("Checkout failed", exception);
log.warn("Retry attempt {}", attempt);
log.info/warn/error/debug call automatically appears in LogNest. MDC values (trace IDs, request IDs) are included as metadata.// Spring Boot auto-configuration registers // a Logback appender automatically when the // JAR is on the classpath. // // Console output on startup: [LogNest] Connected service = 'payment-service' url = 'http://localhost:9000/logs' level = 'DEBUG' // // All logs forwarded asynchronously. // LogNest being down never affects your app.
# application-prod.properties lognest.enabled=false # off in production
npm install lognest-node
const LogNest = require('lognest-node')
const log = new LogNest({ service: 'api-gateway' })
// Use it anywhere
log.info('Server started', { port: 3000 })
log.warn('High memory', { usedMb: 512 })
log.error('Request failed', { userId, endpoint })
const LogNest = require('lognest-node')
// Add this one line at app startup
new LogNest({ service: 'my-app', patchConsole: true })
// All existing console calls now go to LogNest:
console.log('User logged in') // → INFO
console.warn('Slow query') // → WARN
console.error('DB timeout') // → ERROR
// Attach metadata to every log in a request
app.use((req, res, next) => {
req.log = log.child({
requestId: req.id,
userId: req.user?.id,
})
next()
})
// Later in route handlers:
req.log.info('Checkout started')
// → metadata: {requestId, userId} auto-included
new LogNest({
service: 'my-service',
url: 'http://localhost:9000/logs', // default
level: 'DEBUG', // min level to send
enabled: true,
patchConsole: false,
})
pip install lognest
import lognest
lognest.setup(service='ml-pipeline')
# All existing logging calls now go to LogNest:
import logging
logging.error('Model training failed')
logging.warning('Low disk space')
logging.info('Batch job completed')
LOGGING = {
'version': 1,
'handlers': {
'lognest': {
'class': 'lognest.LogNestHandler',
'service': 'django-app',
},
},
'root': {
'handlers': ['lognest'],
'level': 'DEBUG',
},
}
from fastapi import FastAPI
import lognest, logging
# Add at top of main.py — done
lognest.setup(service='fastapi-app')
logger = logging.getLogger(__name__)
app = FastAPI()
@app.get('/checkout')
async def checkout(order_id: str):
logger.info(f'Processing order {order_id}')
# ... your existing code unchanged
logger.error('Payment gateway timeout')
from lognest import LogNestHandler
import logging
handler = LogNestHandler(
service='my-service',
url='http://localhost:9000/logs',
)
handler.setLevel(logging.WARNING) # only WARN+
logging.getLogger().addHandler(handler)
curl -X POST http://localhost:9000/logs \
-H "Content-Type: application/json" \
-d '{
"level": "ERROR",
"service": "payment-service",
"message": "Null pointer at PaymentController:42",
"trace_id": "abc-123",
"timestamp": 1710000000000,
"metadata": {
"userId": "u1",
"orderId": "o99"
}
}'
level, service, message are optional.
timestamp defaults to current time if omitted.
payload := map[string]interface{}{
"level": "ERROR",
"service": "go-service",
"message": err.Error(),
}
data, _ := json.Marshal(payload)
http.Post(
"http://localhost:9000/logs",
"application/json",
bytes.NewBuffer(data),
)
require 'net/http'
require 'json'
uri = URI('http://localhost:9000/logs')
Net::HTTP.post(
uri,
{ level: 'ERROR', service: 'rails-app',
message: e.message }.to_json,
'Content-Type' => 'application/json'
)
$ch = curl_init('http://localhost:9000/logs');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'level' => 'ERROR',
'service' => 'php-app',
'message' => $e->getMessage(),
]));
curl_setopt($ch, CURLOPT_HTTPHEADER,
['Content-Type: application/json']);
curl_exec($ch);
| Field | Type | Required |
|---|---|---|
| level | string | Yes |
| service | string | Yes |
| message | string | Yes |
| timestamp | long (ms) | No |
| trace_id | string | No |
| metadata | JSON object | No |
java -version. Download from adoptium.net if needed.mvn install in the clients/java directory included with LogNest. This installs the starter to your local Maven repository. Then add the <dependency> to your project's pom.xml and set lognest.service=your-app in application.properties. That's all.LN-PRO-20281231-A3F8B2C1-9D4E7F2A within 24 hours. Paste it in Settings → License inside the app. Features activate instantly.lognest-agent.py) is for apps you can't modify — legacy services, third-party binaries, Docker containers, nginx, syslog, etc. Instead of adding a library to your code, you either tail a log file (tail mode) or pipe the process output (pipe mode) and the agent forwards every line to LogNest automatically. It auto-detects the log level from each line. Requires Enterprise license.FATAL / CRITICAL / ERROR / EXCEPTION → ERROR; WARN → WARN; DEBUG / TRACE → DEBUG; INFO → INFO. If no keyword matches, it defaults to INFO. You can also force a fixed level with --level ERROR.Free to download. One dependency install. Your logs appear in seconds.
clients/agent/lognest-agent.py
python lognest-agent.py tail \ --file /var/log/nginx/error.log \ --service nginx
# Spring Boot rolling file python lognest-agent.py tail \ --file logs/app.log \ --service spring-api # Custom LogNest URL python lognest-agent.py tail \ --file app.log --service api \ --url http://localhost:9000
# Legacy app — forward stderr + stdout ./my-legacy-app 2>&1 | python lognest-agent.py pipe \ --service legacy-app # Docker container (live) docker logs -f my-container | python lognest-agent.py pipe \ --service my-container # systemd journal journalctl -f -u my-service | python lognest-agent.py pipe \ --service my-service # nginx access log via tail tail -f /var/log/nginx/access.log | python lognest-agent.py pipe \ --service nginx-access
| Detected Level | Keywords scanned (case-insensitive) |
|---|---|
| ERROR | FATAL, CRITICAL, ERROR, EXCEPTION, SEVERE, TRACEBACK |
| WARN | WARN, WARNING |
| DEBUG | DEBUG, TRACE |
| INFO | INFO |
| INFO (default) | No keyword matched |
--level WARN to force a fixed level for all lines.# Accepts plain text body. Level and service passed as query params. curl -X POST "http://localhost:9000/logs/raw?service=nginx&level=ERROR" \ --header "Content-Type: text/plain" \ --data-binary "2024-01-15 10:23:41 [ERROR] upstream timed out (110) while reading..." # Level is auto-detected from body text if not provided curl -X POST "http://localhost:9000/logs/raw?service=my-app" \ --header "Content-Type: text/plain" \ --data-binary "WARN: High memory usage detected, used=89%"
| Param | Required | Description |
|---|---|---|
| service | Yes | Service name shown in LogNest |
| level | No | Force log level (ERROR/WARN/INFO/DEBUG). If omitted, auto-detected from body text. |
{"id": 42, "status": "ok"} on success. Returns 403 if license is not Enterprise.http://localhost:3000 after starting the app.tail -f. New logs stack at the top up to 500 entries while Live is on.ifconfig en0 | grep "inet " # → inet 192.168.1.100 netmask ...
ipconfig # → IPv4 Address: 192.168.1.100
pip install lognest # Python (recommended — Pi has Python built-in) npm install lognest # Node.js
import lognest
lognest.setup(
service='pi-sensor',
url='http://192.168.1.100:9000/logs'
)
import logging
log = logging.getLogger(__name__)
log.info("Pi started")
log.error("Sensor read failed")
const LogNest = require('lognest')
const log = new LogNest({
service: 'pi-app',
url: 'http://192.168.1.100:9000/logs'
})
log.info('Pi started')
log.error('Sensor read failed')
LOGLITE_URL=http://192.168.1.100:9000/logs as an environment variable and skip the url argument entirely — no code changes needed.# Copy lognest-agent.py to your Pi, then run: python lognest-agent.py tail /var/log/myapp.log \ --service pi-system \ --url http://192.168.1.100:9000/logs # Or pipe any process output directly: journalctl -f | python lognest-agent.py pipe \ --service pi-journal \ --url http://192.168.1.100:9000/logs
# Option 1: Allow the Java process through the macOS app firewall sudo /usr/libexec/ApplicationFirewall/socketfilterfw \ --add $(which java) sudo /usr/libexec/ApplicationFirewall/socketfilterfw \ --unblockapp $(which java) # Option 2: Open port 9000 via pf (packet filter) echo "pass in proto tcp from any to any port 9000" \ | sudo pfctl -ef - # Option 3 (quickest during dev): turn off the app firewall temporarily # System Settings → Network → Firewall → turn off
curl http://192.168.1.100:9000/logs/ping — should return 200 OK.# Run PowerShell as Administrator:
New-NetFirewallRule `
-DisplayName "LogNest port 9000" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 9000 `
-Action Allow
# ufw sudo ufw allow 9000/tcp sudo ufw reload # iptables sudo iptables -A INPUT -p tcp --dport 9000 -j ACCEPT
http://localhost:9000 in your browser to confirm192.168.x.x), not 127.0.0.1ping 192.168.1.100 then curl http://192.168.1.100:9000/logs/pingSend an email to yuliasergeeva596@gmail.com with the subject line matching your plan — e.g. "Starter License" or "Pro License". Include your name and any questions.
Within 24 hours you'll receive a license key in this format:
LN-PRO-20281231-A3F8B2C1-9D4E7F2A
The key encodes your plan tier, expiry date, and a unique buyer token tied to your email. It's verified fully offline — no internet required to activate.
Click the Settings tab in the top navigation bar of the LogNest dashboard.
Paste the key into the license input field and click Activate. Features unlock immediately — no restart, no internet, no account.
The tier badge in the top bar updates. Locked features (Charts, Alerts, Presets, Export) become fully available right away. The key is saved — it persists across restarts.
http://localhost:9000| Method | Endpoint | Description | Plan |
|---|---|---|---|
| POST | /logs | Ingest a log entry. Body: level, service, message (required) + timestamp, trace_id, metadata (optional) |
Free |
| GET | /logs | Query logs. Params: level service search from to limit (default 100) |
Free |
| GET | /logs/stream | Server-Sent Events stream. Emits log events for new logs and alert events when alert rules fire. |
Free |
| DELETE | /logs | Delete all stored logs. | Free |
| GET | /logs/export | Download logs as file. Params: format=csv|json, same filters as GET /logs. |
Starter+ |
| GET | /settings | Get current app settings. Returns sessionClear (bool) and sessionClearEnabled (bool based on license). |
Free |
| POST | /settings | Update app settings. Body: {"sessionClear": true}. Clears all logs on next startup when enabled. |
Starter+ |
| GET/POST/DELETE | /presets | Saved filter presets. POST body: name, level, service, search. |
Starter+ |
| GET | /analytics/stats | Error counts by time bucket. Params: windowMinutes (default 60), bucketMinutes (default 5). |
Pro+ |
| GET/POST/PUT/DELETE | /alerts | Alert rules. POST body: name, level, thresholdCount, windowMinutes, enabled. |
Pro+ |
| POST | /logs/raw | Ingest plain text log line. Params: service (required), level (optional — auto-detected from body if omitted). Body: plain text. |
Enterprise |
| GET | /license | Returns current tier and feature flags: tier, logLimit, exportEnabled, chartsEnabled, alertsEnabled, etc. |
Free |
| POST | /license/activate | Activate a license key. Body: {"key": "LN-PRO-20281231-XXXXXXXX"}. Returns success and tier. |
Free |
// POST /logs → 200 { "id": 42, "status": "ok" } // GET /logs?level=ERROR&limit=2 [ { "id": 42, "timestamp": 1710000000000, "level": "ERROR", "service": "payment-service", "message": "NPE at PaymentController:42", "traceId": "abc-123", "metadata": { "userId": "u1" } } ]
// GET /license { "tier": "PRO", "logLimit": 100000, "retentionDays": 90, "exportEnabled": true, "chartsEnabled": true, "alertsEnabled": true, "presetsEnabled": true } // POST /license/activate { "success": true, "tier": "PRO" }