Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions examples/basic.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dotenv/config'
import { pino } from 'pino'
import { LokiOptions } from '../src/types/index'
import { LokiOptions, LokiLogLevel } from '../src/types/index'

const transport = pino.transport<LokiOptions>({
// 👇 Replace this with "pino-loki"
Expand All @@ -9,7 +9,11 @@ const transport = pino.transport<LokiOptions>({
options: {
// These labels will be added to every log
labels: { application: 'MY-APP' },

// custom log levels
levelMap: {
'5': LokiLogLevel.Debug, // Add a custom log level
'10': LokiLogLevel.Info, // Override a default mapping
},
// Credentials for our Loki instance
host: process.env.LOKI_HOST!,
basicAuth: {
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import abstractTransportBuild from 'pino-abstract-transport'
import { PinoLog, LokiOptions } from './types/index'
import { PinoLog, LokiOptions, LokiLogLevel } from './types/index'
import { LogPusher } from './log_pusher/index'
import debug from './debug'

Expand Down Expand Up @@ -68,3 +68,4 @@ function pinoLoki(userOptions: LokiOptions) {

export default pinoLoki
export type { LokiOptions }
export { LokiLogLevel }
30 changes: 17 additions & 13 deletions src/log_builder/index.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import { LokiLog, LokiLogLevel, PinoLog } from '../types/index'
import { LokiLog, LokiLogLevel, PinoLog, LokiOptions } from '../types/index'

const NANOSECONDS_LENGTH = 19

type BuilderOptions = Pick<LokiOptions, 'propsToLabels' | 'levelMap'>

/**
* Converts a Pino log to a Loki log
*/
export class LogBuilder {
#propsToLabel: string[]

constructor(propsToLabel: string[] = []) {
this.#propsToLabel = propsToLabel
}
#propsToLabels: string[]
#levelMap: { [key: number]: LokiLogLevel }

/**
* Convert a level to a human readable status
*/
public statusFromLevel(level: number) {
return (
constructor(options?: BuilderOptions) {
this.#propsToLabels = options?.propsToLabels || []
this.#levelMap = Object.assign(
{
10: LokiLogLevel.Debug,
20: LokiLogLevel.Debug,
30: LokiLogLevel.Info,
40: LokiLogLevel.Warning,
50: LokiLogLevel.Error,
60: LokiLogLevel.Critical,
}[level] || LokiLogLevel.Info
},
options?.levelMap,
)
}

/**
* Convert a level to a human readable status
*/
public statusFromLevel(level: number) {
return this.#levelMap[level] || LokiLogLevel.Info
}
/**
* Builds a timestamp string from a Pino log object.
* @returns A string representing the timestamp in nanoseconds.
Expand All @@ -53,7 +57,7 @@ export class LogBuilder {
#buildLabelsFromProps(log: PinoLog) {
const labels: Record<string, string> = {}

for (const prop of this.#propsToLabel) {
for (const prop of this.#propsToLabels) {
if (log[prop]) {
labels[prop] = log[prop]
}
Expand Down
6 changes: 4 additions & 2 deletions src/log_pusher/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ export class LogPusher {
}),
})

const propsToLabels = options.propsToLabels || []
this.#logBuilder = new LogBuilder(propsToLabels)
this.#logBuilder = new LogBuilder({
levelMap: options.levelMap,
propsToLabels: options.propsToLabels,
})
}

/**
Expand Down
15 changes: 15 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ export interface LokiOptions {
[key: string]: string
}

/**
* Custom pino to loki log level mapping, merged with the default one.
* @default
* 10: LokiLogLevel.Debug,
20: LokiLogLevel.Debug,
30: LokiLogLevel.Info,
40: LokiLogLevel.Warning,
50: LokiLogLevel.Error,
60: LokiLogLevel.Critical
*/

levelMap?: {
[key: number]: LokiLogLevel
}

/**
* Basic auth credentials to be used when sending logs to Loki
*/
Expand Down
17 changes: 15 additions & 2 deletions tests/unit/log_builder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test } from '@japa/runner'
import { PinoLog } from '../../src/types/index'
import { LokiLogLevel, PinoLog } from '../../src/types/index'
import { LogBuilder } from '../../src/log_builder/index'
import { sleep } from '../../src/utils/index'

Expand All @@ -23,6 +23,19 @@ test.group('Log Builder', () => {
assert.deepEqual(logBuilder.statusFromLevel(60), 'critical')
})

test('Custom levels', ({ assert }) => {
const logBuilder = new LogBuilder({
levelMap: { '5': LokiLogLevel.Debug, '20': LokiLogLevel.Info },
})
assert.deepEqual(logBuilder.statusFromLevel(5), 'debug') // custom
assert.deepEqual(logBuilder.statusFromLevel(10), 'debug')
assert.deepEqual(logBuilder.statusFromLevel(20), 'info') // override
assert.deepEqual(logBuilder.statusFromLevel(30), 'info')
assert.deepEqual(logBuilder.statusFromLevel(40), 'warning')
assert.deepEqual(logBuilder.statusFromLevel(50), 'error')
assert.deepEqual(logBuilder.statusFromLevel(60), 'critical')
})

test('Build a loki log entry from a pino log', ({ assert }) => {
const logBuilder = new LogBuilder()

Expand Down Expand Up @@ -66,7 +79,7 @@ test.group('Log Builder', () => {
})

test('Props to label', ({ assert }) => {
const logBuilder = new LogBuilder(['appId', 'buildId'])
const logBuilder = new LogBuilder({ propsToLabels: ['appId', 'buildId'] })

const log: PinoLog = {
hostname: 'localhost',
Expand Down