added LOKI_FLUSH_INTERVAL_MS
This commit is contained in:
parent
4ab83d1dc2
commit
62baac7640
5 changed files with 6 additions and 87 deletions
|
|
@ -121,6 +121,7 @@ LOKI_USERNAME=
|
||||||
LOKI_PASSWORD=
|
LOKI_PASSWORD=
|
||||||
LOKI_TENANT_ID=
|
LOKI_TENANT_ID=
|
||||||
LOKI_PUSH_TIMEOUT=10000
|
LOKI_PUSH_TIMEOUT=10000
|
||||||
|
LOKI_FLUSH_INTERVAL_MS=5000
|
||||||
LOKI_BATCH_SIZE=1024
|
LOKI_BATCH_SIZE=1024
|
||||||
LOKI_BATCH_WAIT=1000
|
LOKI_BATCH_WAIT=1000
|
||||||
LOKI_RETENTION_PERIOD=30d
|
LOKI_RETENTION_PERIOD=30d
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ LOKI_USERNAME=${LOKI_USERNAME}
|
||||||
LOKI_PASSWORD=${LOKI_PASSWORD}
|
LOKI_PASSWORD=${LOKI_PASSWORD}
|
||||||
LOKI_TENANT_ID=${LOKI_TENANT_ID}
|
LOKI_TENANT_ID=${LOKI_TENANT_ID}
|
||||||
LOKI_PUSH_TIMEOUT=30000
|
LOKI_PUSH_TIMEOUT=30000
|
||||||
|
LOKI_FLUSH_INTERVAL_MS=5000
|
||||||
LOKI_BATCH_SIZE=2048
|
LOKI_BATCH_SIZE=2048
|
||||||
LOKI_BATCH_WAIT=5000
|
LOKI_BATCH_WAIT=5000
|
||||||
LOKI_RETENTION_PERIOD=90d
|
LOKI_RETENTION_PERIOD=90d
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ export const lokiConfig = cleanEnv(process.env, {
|
||||||
LOKI_DEFAULT_LABELS: str({ default: '', desc: 'Default labels for all log entries (JSON format)' }),
|
LOKI_DEFAULT_LABELS: str({ default: '', desc: 'Default labels for all log entries (JSON format)' }),
|
||||||
LOKI_SERVICE_LABEL: str({ default: 'stock-bot', desc: 'Service label for log entries' }),
|
LOKI_SERVICE_LABEL: str({ default: 'stock-bot', desc: 'Service label for log entries' }),
|
||||||
LOKI_ENVIRONMENT_LABEL: str({ default: 'development', desc: 'Environment label for log entries' }),
|
LOKI_ENVIRONMENT_LABEL: str({ default: 'development', desc: 'Environment label for log entries' }),
|
||||||
|
|
||||||
|
LOKI_FLUSH_INTERVAL_MS: num({ default: 5000, desc: 'Flush interval ms' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export typed configuration object
|
// Export typed configuration object
|
||||||
|
|
@ -58,4 +60,5 @@ export const {
|
||||||
LOKI_DEFAULT_LABELS,
|
LOKI_DEFAULT_LABELS,
|
||||||
LOKI_SERVICE_LABEL,
|
LOKI_SERVICE_LABEL,
|
||||||
LOKI_ENVIRONMENT_LABEL,
|
LOKI_ENVIRONMENT_LABEL,
|
||||||
|
LOKI_FLUSH_INTERVAL_MS,
|
||||||
} = lokiConfig;
|
} = lokiConfig;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export * from './dateUtils';
|
export * from './dateUtils';
|
||||||
export * from './logger';
|
export * from './logger';
|
||||||
export * from './lokiClient.ts';
|
export * from './calculations/index';
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
/**
|
|
||||||
* Loki client for sending logs to Grafana Loki
|
|
||||||
*/
|
|
||||||
import { LoggingConfig } from '@stock-bot/config';
|
|
||||||
|
|
||||||
export class LokiClient {
|
|
||||||
private batchQueue: any[] = [];
|
|
||||||
private flushInterval: NodeJS.Timeout;
|
|
||||||
private lokiUrl: string;
|
|
||||||
private authHeader?: string;
|
|
||||||
|
|
||||||
constructor(private config: LoggingConfig) {
|
|
||||||
const { host, port, username, password } = config.loki;
|
|
||||||
|
|
||||||
this.lokiUrl = `http://${host}:${port}/loki/api/v1/push`;
|
|
||||||
|
|
||||||
if (username && password) {
|
|
||||||
const authString = Buffer.from(`${username}:${password}`).toString('base64');
|
|
||||||
this.authHeader = `Basic ${authString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.flushInterval = setInterval(
|
|
||||||
() => this.flush(),
|
|
||||||
config.loki.flushIntervalMs
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async log(level: string, message: string, serviceName: string, labels: Record<string, string> = {}) {
|
|
||||||
const timestamp = Date.now() * 1000000; // Loki expects nanoseconds
|
|
||||||
|
|
||||||
this.batchQueue.push({
|
|
||||||
streams: [{
|
|
||||||
stream: {
|
|
||||||
level,
|
|
||||||
service: serviceName,
|
|
||||||
...this.config.loki.labels,
|
|
||||||
...labels,
|
|
||||||
},
|
|
||||||
values: [[`${timestamp}`, message]],
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.batchQueue.length >= this.config.loki.batchSize) {
|
|
||||||
await this.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async flush() {
|
|
||||||
if (this.batchQueue.length === 0) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const headers: Record<string, string> = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.authHeader) {
|
|
||||||
headers['Authorization'] = this.authHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(this.lokiUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
streams: this.batchQueue.flatMap(batch => batch.streams),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error(`Failed to send logs to Loki: ${response.status} ${response.statusText}`);
|
|
||||||
const text = await response.text();
|
|
||||||
if (text) {
|
|
||||||
console.error(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error sending logs to Loki:', error);
|
|
||||||
} finally {
|
|
||||||
this.batchQueue = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async destroy() {
|
|
||||||
clearInterval(this.flushInterval);
|
|
||||||
return this.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue