Skip to content

Instantly share code, notes, and snippets.

@jordanebelanger
Last active June 2, 2023 21:09
Show Gist options
  • Save jordanebelanger/175417f1b61fa2c452fab0cdf3c53570 to your computer and use it in GitHub Desktop.
Save jordanebelanger/175417f1b61fa2c452fab0cdf3c53570 to your computer and use it in GitHub Desktop.
Fastify GCP Stackdriver logging agent compatible pino logger
import * as P from 'pino'
import {FastifyReply, FastifyRequest} from 'fastify'
const enum PINO_LEVELS {
trace = 10,
debug = 20,
info = 30,
warn = 40,
error = 50,
fatal = 60,
}
function pinoLevelToStackdriverSeverity(level: PINO_LEVELS) {
if (level === PINO_LEVELS.trace || level === PINO_LEVELS.debug) {
return 'debug'
}
if (level === PINO_LEVELS.info) {
return 'info'
}
if (level === PINO_LEVELS.warn) {
return 'warning'
}
if (level === PINO_LEVELS.error) {
return 'error'
}
if (level >= PINO_LEVELS.fatal) {
return 'critical'
}
return 'default'
}
function truncateToDecimalPlace(value: number, decimalPlace: number) {
return (
Math.trunc(value * Math.pow(10, decimalPlace)) / Math.pow(10, decimalPlace)
)
}
interface LogEntryHTTPRequest {
requestMethod?: string
requestUrl?: string
requestSize?: string
status?: number
responseSize?: string
userAgent?: string
remoteIp?: string
serverIp?: string
referer?: string
latency?: string
cacheLookup?: boolean
cacheHit?: boolean
cacheValidatedWithOriginServer?: boolean
cacheFillBytes?: string
protocol?: string
}
interface LogObject {
req?: FastifyRequest
res?: FastifyReply
httpRequest?: LogEntryHTTPRequest
requestId?: string
}
const logger = P({
messageKey: 'message',
timestamp: false,
base: undefined,
formatters: {
level(_label, number) {
return {
severity: pinoLevelToStackdriverSeverity(number),
}
},
log(object: LogObject) {
// Setuping the Stackdriver httpRequest property on the log entry
if (object.req) {
object.httpRequest = {
...(object.httpRequest ?? {},
{
requestMethod: object.req.method,
requestUrl: object.req.url,
userAgent: object.req.headers['user-agent'],
remoteIp: object.req.ip,
protocol: object.req.protocol,
})
}
}
if (object.res) {
object.httpRequest = {
...(object.httpRequest ?? {},
{
requestMethod: object.res.request.method,
requestUrl: object.res.request.url,
status: object.res.statusCode,
userAgent: object.res.request.headers['user-agent'],
latency: `${truncateToDecimalPlace(object.res.getResponseTime() / 1000, 9)}s`,
remoteIp: object.res.request.ip,
protocol: object.res.request.protocol,
}),
}
}
return object
}
},
serializers: {
// Nullifying the standard Fastify Request/Response serializer for better stackdriver support
req(request: FastifyRequest) { return undefined },
res(reply: FastifyReply) { return undefined },
responseTime: function(value) { return undefined }
}
})
export default logger
@narkeeso
Copy link

narkeeso commented Sep 8, 2021

Thank you for posting this! Was driving crazy trying to find an easy way to get pino to behave with stackdriver.

@jordanebelanger
Copy link
Author

Thank you for posting this! Was driving crazy trying to find an easy way to get pino to behave with stackdriver.

My pleasure, it is definately tricky and a bit of a hack job to make it work good 😓

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment