Add the ability to log to loki
This commit is contained in:
@@ -3,7 +3,13 @@ import { join } from "node:path";
|
||||
import crypto from "node:crypto";
|
||||
import db, { nowIso } from "./db";
|
||||
import { config } from "./config";
|
||||
import { getCloudflareSettings, getGeneralSettings, getMetricsSettings, setSetting } from "./settings";
|
||||
import {
|
||||
getCloudflareSettings,
|
||||
getGeneralSettings,
|
||||
getLoggingSettings,
|
||||
getMetricsSettings,
|
||||
setSetting
|
||||
} from "./settings";
|
||||
import {
|
||||
accessListEntries,
|
||||
certificates,
|
||||
@@ -782,6 +788,60 @@ async function buildTlsAutomation(
|
||||
};
|
||||
}
|
||||
|
||||
function buildLoggingApp(loggingSettings: NonNullable<Awaited<ReturnType<typeof getLoggingSettings>>>) {
|
||||
if (!loggingSettings.lokiUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const lokiWriterConfig: Record<string, unknown> = {
|
||||
output: "loki",
|
||||
url: loggingSettings.lokiUrl
|
||||
};
|
||||
|
||||
// Add basic auth if provided
|
||||
if (loggingSettings.lokiUsername && loggingSettings.lokiPassword) {
|
||||
lokiWriterConfig.username = loggingSettings.lokiUsername;
|
||||
lokiWriterConfig.password = loggingSettings.lokiPassword;
|
||||
}
|
||||
|
||||
// Add custom labels if provided
|
||||
if (loggingSettings.labels && Object.keys(loggingSettings.labels).length > 0) {
|
||||
lokiWriterConfig.labels = loggingSettings.labels;
|
||||
}
|
||||
|
||||
return {
|
||||
logs: {
|
||||
// Access log for all HTTP requests
|
||||
access: {
|
||||
encoder: {
|
||||
format: "json",
|
||||
message_key: "msg",
|
||||
level_key: "level",
|
||||
time_key: "ts",
|
||||
name_key: "logger"
|
||||
},
|
||||
writer: lokiWriterConfig,
|
||||
level: "INFO",
|
||||
include: ["http.log.access.*"]
|
||||
},
|
||||
// Default log for errors and other messages
|
||||
default: {
|
||||
encoder: {
|
||||
format: "json",
|
||||
message_key: "msg",
|
||||
level_key: "level",
|
||||
time_key: "ts",
|
||||
name_key: "logger",
|
||||
caller_key: "caller",
|
||||
stacktrace_key: "stacktrace"
|
||||
},
|
||||
writer: lokiWriterConfig,
|
||||
level: "WARN"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function buildCaddyDocument() {
|
||||
const [proxyHostRecords, redirectHostRecords, deadHostRecords, certRows, accessListEntryRecords] = await Promise.all([
|
||||
db
|
||||
@@ -930,6 +990,11 @@ async function buildCaddyDocument() {
|
||||
const metricsEnabled = metricsSettings?.enabled ?? false;
|
||||
const metricsPort = metricsSettings?.port ?? 9090;
|
||||
|
||||
// Check if logging should be enabled
|
||||
const loggingSettings = await getLoggingSettings();
|
||||
const loggingEnabled = loggingSettings?.enabled ?? false;
|
||||
const loggingApp = loggingEnabled && loggingSettings ? buildLoggingApp(loggingSettings) : null;
|
||||
|
||||
const servers: Record<string, unknown> = {};
|
||||
|
||||
// Main HTTP/HTTPS server for proxy hosts
|
||||
@@ -940,7 +1005,9 @@ async function buildCaddyDocument() {
|
||||
// Only disable automatic HTTPS if we have TLS automation policies
|
||||
// This allows Caddy to handle HTTP-01 challenges for managed certificates
|
||||
...(tlsApp ? {} : { automatic_https: { disable: true } }),
|
||||
...(hasTls ? { tls_connection_policies: tlsConnectionPolicies } : {})
|
||||
...(hasTls ? { tls_connection_policies: tlsConnectionPolicies } : {}),
|
||||
// Enable access logging if configured
|
||||
...(loggingEnabled ? { logs: { default_logger_name: "access" } } : {})
|
||||
};
|
||||
}
|
||||
|
||||
@@ -972,7 +1039,8 @@ async function buildCaddyDocument() {
|
||||
},
|
||||
apps: {
|
||||
...httpApp,
|
||||
...(tlsApp ? { tls: tlsApp } : {})
|
||||
...(tlsApp ? { tls: tlsApp } : {}),
|
||||
...(loggingApp ? { logging: loggingApp } : {})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ export type MetricsSettings = {
|
||||
port?: number; // Port to expose metrics on (default: 9090, separate from admin API)
|
||||
};
|
||||
|
||||
export type LoggingSettings = {
|
||||
enabled: boolean;
|
||||
lokiUrl?: string; // URL of Loki instance (e.g., http://loki:3100)
|
||||
lokiUsername?: string; // Optional username for Loki authentication
|
||||
lokiPassword?: string; // Optional password for Loki authentication
|
||||
labels?: Record<string, string>; // Optional custom labels for logs
|
||||
};
|
||||
|
||||
export async function getSetting<T>(key: string): Promise<SettingValue<T>> {
|
||||
const setting = await db.query.settings.findFirst({
|
||||
where: (table, { eq }) => eq(table.key, key)
|
||||
@@ -94,3 +102,11 @@ export async function getMetricsSettings(): Promise<MetricsSettings | null> {
|
||||
export async function saveMetricsSettings(settings: MetricsSettings): Promise<void> {
|
||||
await setSetting("metrics", settings);
|
||||
}
|
||||
|
||||
export async function getLoggingSettings(): Promise<LoggingSettings | null> {
|
||||
return await getSetting<LoggingSettings>("logging");
|
||||
}
|
||||
|
||||
export async function saveLoggingSettings(settings: LoggingSettings): Promise<void> {
|
||||
await setSetting("logging", settings);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user