Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: log using custom msg #31

Merged
merged 5 commits into from
Oct 26, 2023
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
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ app.register(mercuriusLogging, {
logBody: true, // default: false
logVariables: true, // default: false
logRequest: true // default: false
logMessage: function(context) // default: undefined
})
```

Expand Down Expand Up @@ -243,6 +244,63 @@ If you want to include the request's variables in the log output, set this optio
```


### logMessage

If you want to put a custom message inside the log output, you can set this option as a `function(context)` which returns a `string` or an `array` containing Pino supported values.

#### Example returning a string

```js
app.register(mercuriusLogging, {
logMessage: function (context) {
return `This is a request made with method ${context.reply.request.method}`
}
})
```

Here's an output example

```json
{
"level": 30,
"graphql": {
"queries": [
"firstQuery:myTeam",
"secondQuery:myTeam"
]
},
"msg": "This is a request made with method POST"
}
```

#### Example returning an array

```js
app.register(mercuriusLogging, {
logMessage: function (context) {
return ['This is a request made with method %s by foo%s', context.reply.request.method, 'bar' ]
}
})
```

Here's an output example

```json
{
"level": 30,
"graphql": {
"queries": [
"firstQuery:myTeam",
"secondQuery:myTeam"
]
},
"msg": "This is a request made with method POST by foobar"
}
```




## License

Copyright [Manuel Spigolon](https://github.com/Eomm), Licensed under [MIT](./LICENSE).
29 changes: 26 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@ function conditionalBody (fn, context, body) {
return undefined
}

function customLogMessage (fn, context) {
try {
return fn(context)
} catch (error) {
context.app.log.debug(error, 'mercurius-logging: error in logMessage function')
}
return undefined
}

function mercuriusLogging (app, opts, next) {
const options = Object.assign({}, {
logLevel: 'info',
prependAlias: false,
logBody: false,
logVariables: false,
logRequest: false
logRequest: false,
logMessage: undefined
}, opts)

options.buildBody = opts.logBody === true
Expand All @@ -36,6 +46,10 @@ function mercuriusLogging (app, opts, next) {
? conditionalBody.bind(null, opts.logBody)
: noop

options.buildLogMessage = typeof opts.logMessage === 'function'
? customLogMessage.bind(null, opts.logMessage)
: undefined

app.graphql.addHook('preExecution', logGraphQLDetails.bind(null, options))
next()
}
Expand Down Expand Up @@ -66,7 +80,7 @@ function logGraphQLDetails (opts, schema, document, context) {
? requestBody.find(isCurrentOperation)
: requestBody

context.reply.request.log[opts.logLevel]({
const logData = {
req: opts.logRequest === true ? context.reply.request : undefined,
graphql: {
queries: queryOps.length > 0 ? queryOps : undefined,
Expand All @@ -75,7 +89,16 @@ function logGraphQLDetails (opts, schema, document, context) {
body: opts.buildBody(context, currentBody),
variables: opts.logVariables === true ? currentBody?.variables || null : undefined
}
})
}

const logMessage = opts.buildLogMessage?.(context)

if (!logMessage) {
context.reply.request.log[opts.logLevel](logData)
return
}

context.reply.request.log[opts.logLevel].apply(context.reply.request.log, [logData].concat(logMessage))
}

function readOperationName (document) {
Expand Down
246 changes: 246 additions & 0 deletions test/logMessage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
'use strict'

const test = require('ava')
const { buildApp, jsonLogger } = require('./_helper')

test('should log without msg when logMessage is undefined', async (t) => {
t.plan(5)

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, undefined)
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})

test('should log without msg when logMessage is\'nt a valid function', async (t) => {
t.plan(5)

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, undefined)
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream }, { logMessage: 1234 })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})

test('should log without msg using a logMessage function returning an undefined value', async (t) => {
t.plan(5)

const customLogMessage = (context) => undefined

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, undefined)
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream }, { logMessage: customLogMessage })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})

test('should log without msg using a logMessage function throwing an error', async (t) => {
t.plan(5)

const customLogMessage = (context) => { throw new Error() }

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, undefined)
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream }, { logMessage: customLogMessage })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})

test('should log with msg using a logMessage function returning a string', async (t) => {
t.plan(5)

const customLogMessage = (context) => `This is a request made with method ${context.reply.request.method}`

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, 'This is a request made with method POST')
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream }, { logMessage: customLogMessage })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})

test('should log with msg using a logMessage function returning an array', async (t) => {
t.plan(5)

const customLogMessage = (context) => [`This is a request made with method ${context.reply.request.method} by foo%s`, 'bar']

const stream = jsonLogger(
line => {
t.is(line.req, undefined)
t.is(line.reqId, 'req-1')
t.deepEqual(line.msg, 'This is a request made with method POST by foobar')
t.deepEqual(line.graphql, {
operationName: 'logMe',
queries: ['add', 'add', 'echo', 'counter']
})
})

const app = buildApp(t, { stream }, { logMessage: customLogMessage })

const query = `query logMe{
four: add(x: 2, y: 2)
six: add(x: 3, y: 3)
echo(msg: "hello")
counter
}`

const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.deepEqual(response.json(), {
data: {
four: 4,
six: 6,
echo: 'hellohello',
counter: 0
}
})
})