Closed ovasdi closed 1 year ago
Merging #3102 (cd72896) into main (9d19fbf) will increase coverage by
0.0%
. The diff coverage is100.0%
.
@@ Coverage Diff @@
## main #3102 +/- ##
=====================================
Coverage 83.0% 83.0%
=====================================
Files 197 198 +1
Lines 5416 5420 +4
Branches 989 989
=====================================
+ Hits 4500 4504 +4
Misses 663 663
Partials 253 253
RE: the question, do we want to change the structure of the log output? If so, how?
I think the default format looks OK, for the most part, but it does feel quite busy and IMO there are some fields that we could eliminate or rename, to make them more clear:
The following fields seem not very useful:
req.id
: remove
req.headers.connection
: remove
req.headers.sec-ch-ua*
: remove
req.headers.upgrade-insecure-requests
: remove
req.headers.sec-fetch*
: remove (though sec-fetch-site
may be useful to keep?)
On that note, I liked the example that is listed in the OWASP logging cheat sheet. I wonder if it would be worth following that example more closely. This would necessitate some heavy formating customization tho.
Another question I am contemplating is regarding log format when running in development
vs production
mode. How different do we the format to be between environments? I would think we would want only what is most useful. Hence why I like the OWASP example. It seems quite lean compared to the Pino default. I also like that it's not nested.
This is a lot more data than we currently log! On the one hand, I could see that being useful (e.g., Cloudflare headers available in logs), on the other, we're already trending toward exhausting our quota regularly, and a lot of the headers are noise. I would consider removing all the request and response headers, or maybe all but a few interesting ones (User-agent
, Accept
...).
Curious what others think.
I agree with cutting down the defaults here that we don't anticipate providing much value, though I do think that one of the nice things about the new JSON
format gives us the ability to log more without it generating too much more visual noise since we can collapse or expand the JSON
string in papertrail. In other words, I would vote to cut down the current output form peno
outputs, but think we should feel free to leverage the more readable JSON
format where it makes sense for this or other repos.
I think using the OWASP format you linked to @ovasdi is a reasonable start. It would also be good to see how much work it takes to customize the output in peno
.
I started to customize the httpLogger
and quickly learned that a bug in pino-http causes cutomProps
, logger option for adding custom properties, to get logged twice...
Looking if similar customization can be achieved using the formatters.log API otherwise will need some workaround.
I was not able to come up with a working and clean workaround to fully customize the httpLogger
. My plan was to remove all of req
and res
from the httpLogger
and build a one level object, similar to the example mentioned earlier, with only the properties that we would want to see. I ended up expanding the redact.paths
list to remove the various properties we don't care about. This isn't ideal and not super portable.
I am happy to work out a better solution if this approach isn't sufficient.
I am just realizing I dismissed this workaround thinking WeakSet
is only supported in Node v14+ but it seems it may be supported in earlier versions as well. Will give this a try tomorrow.
The latest changes in b1165f1 refactors the logger to include a custom serializer which operates on req
and res
objects specifying which properties to keep. This eliminates the need for using the redact
API to remove sensitive values from logs.
I also added a custom message for received requests to make it easier to identify incoming requests.
There are a number of requests that contain the message 'request errored'. These do complete successfully, with status code 200 or 304. Unclear why the logger is including the 'errored' message but appears to mostly affect: /api/sessions
, /api/graphql
, /api/channels
.
I don't follow the need for the custom "request received" lines. It's pretty standard to log upon request completion, which I think is already achieved by default (even if the request fails).
I removed this. I was looking at an outdated copy of logs and didn't realize that adding this option actually enables additional logs to be output for 'received requests'. Thanks for pointing this out.
Can you explain those other customizations around pid, timestamp, and level?
pid
I thought was not very useful, so removed it. Do you think it should remain?timestamp
is logged in Milliseconds since Unix epoch (by default) so I chose to make it more human-readable and format it using the recommended stdTimeFunction
which comes from pino
.
pino
to get imported. I didn't think this was an issue but if its better to remove that import, I can either leave the value as is or see about formatting the value without using the stdTimeFunction
.responseTime
is included, I did not remove it. But as mentioned above, the received requests in the last log sample do not have responseTime
property.After discussing with @joeyAghion all options but one were removed. The only option remaining is the custom serializer which lists the properties of req
and res
we want to see in the logged output. Everything else is the default.
Find additional context in this slack thread
https://artsyproduct.atlassian.net/browse/PLATFORM-4903
This PR introduces a new logger Pino (replacing artsy-morgan) for the purposes of proving out a POC which is about standardizing our logging posture across Artsy applications and specifically as it pertains to web apps.
Few reasons for choosing pino over the other alternatives (eg: winston) are:
Note that this PR uses pino
v7.11.0
and pino-httpv7.1.0
seeing as Positron is currently on Node12 and pino[-http] v8 (latest) does not have LTS support for Node12, according to this schedule table.The implementation in this PR replaced only the middleware logging. In case of Positron, the app has a number of lines being logged using
console.log
. Those have not been touched for this POC.I did not spend a lot of time configuring log output. As agreed upon during the last velocity mob session, this PR is mostly using defaults that come out of the box when using Pino library.
If this was to get merged as is, as far viewing logs in papertrail, I believe we would see something similar to
kube-api logs
but for Positron requests.Some questions for PR discussion:
NOTE: sensitive information has been removed from the logs (via logger configuration), namely:
x-access-token
andcookie
, which are logged by default with the whole request object. The timestamp has been formatted to be more human-readable.Below is an example request for the purposes of demonstration and discussion:
request path:
/
artsy-morgan
``` GET / 302 3.278 ms - 62 POST /api/graphql 200 1816.408 ms - - GET /api/sessions 200 106.931 ms - 2 GET /articles 304 2315.606 ms - - GET /assets/main.css 304 51.697 ms - - GET /icons/search.svg 304 6.397 ms - - [socket] onArticlesRequested, channel id: [REDACTED] GET /images/favicon.ico 304 146.969 ms - - GET /api/sessions 200 145.264 ms - 2 GET /api/channels?user_id=[REDACTED]&limit=50 304 457.635 ms - - ```pino
```JSON { "level": "info", "time": "2023-01-27T18:00:35.205Z", "req": { "id": 51, "method": "GET", "url": "/", "query": {}, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "sec-fetch-site": "same-origin", "sec-fetch-mode": "navigate", "sec-fetch-user": "?1", "sec-fetch-dest": "document", "referer": "http://localhost:3005/settings", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9" }, "remoteAddress": "::1", "remotePort": 56443 }, "res": { "statusCode": 302, "headers": { "x-powered-by": "Express", "x-frame-options": "SAMEORIGIN", "location": "/articles", "vary": "Accept, Accept-Encoding", "content-type": "text/html; charset=utf-8", "content-length": "62" } }, "responseTime": 4, "msg": "request completed" }, { "level": "info", "time": "2023-01-27T18:00:35.760Z", "req": { "id": 53, "method": "POST", "url": "/api/graphql", "query": {}, "params": {}, "headers": { "accept": "application/json", "content-type": "application/json", "accept-encoding": "gzip,deflate", "user-agent": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)", "connection": "close", "content-length": "348", "x-datadog-trace-id": "[REDACTED]", "x-datadog-parent-id": "[REDACTED]", "x-datadog-sampling-priority": "1", "host": "localhost:3005" }, "remoteAddress": "::ffff:127.0.0.1", "remotePort": 56444 }, "res": { "statusCode": 200, "headers": { "x-powered-by": "Express", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "vary": "Accept-Encoding", "content-encoding": "gzip" } }, "responseTime": 516, "msg": "request errored" }, { "level": "info", "time": "2023-01-27T18:00:35.865Z", "req": { "id": 54, "method": "GET", "url": "/api/sessions", "query": {}, "params": {}, "headers": { "x-datadog-trace-id": "[REDACTED]", "x-datadog-parent-id": "[REDACTED]", "x-datadog-sampling-priority": "1", "host": "localhost:3005", "accept-encoding": "gzip, deflate", "connection": "close" }, "remoteAddress": "::ffff:127.0.0.1", "remotePort": 56445 }, "res": { "statusCode": 200, "headers": { "x-powered-by": "Express", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "content-length": "2", "etag": "W/\"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w\"", "vary": "Accept-Encoding" } }, "responseTime": 97, "msg": "request errored" }, { "level": "info", "time": "2023-01-27T18:00:35.920Z", "req": { "id": 52, "method": "GET", "url": "/articles", "query": {}, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "sec-fetch-site": "same-origin", "sec-fetch-mode": "navigate", "sec-fetch-user": "?1", "sec-fetch-dest": "document", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "referer": "http://localhost:3005/settings", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "if-none-match": "W/\"3999-bNG7tLn35AyW0ot1tLksYgZfGX4\"" }, "remoteAddress": "::1", "remotePort": 56443 }, "res": { "statusCode": 304, "headers": { "x-powered-by": "Express", "x-frame-options": "SAMEORIGIN", "etag": "W/\"3999-bNG7tLn35AyW0ot1tLksYgZfGX4\"" } }, "responseTime": 688, "msg": "request completed" }, { "level": "info", "time": "2023-01-27T18:00:36.012Z", "req": { "id": 55, "method": "GET", "url": "/assets/main.css", "query": {}, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "if-none-match": "W/\"19b18-185f4279dbb\"", "if-modified-since": "Fri, 27 Jan 2023 16:55:15 GMT", "sec-ch-ua-mobile": "?0", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "sec-ch-ua-platform": "\"macOS\"", "accept": "text/css,*/*;q=0.1", "sec-fetch-site": "same-origin", "sec-fetch-mode": "no-cors", "sec-fetch-dest": "style", "referer": "http://localhost:3005/articles", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9" }, "remoteAddress": "::1", "remotePort": 56443 }, "res": { "statusCode": 304, "headers": { "x-powered-by": "Express", "x-frame-options": "SAMEORIGIN", "accept-ranges": "bytes", "cache-control": "public, max-age=0", "last-modified": "Fri, 27 Jan 2023 16:55:15 GMT", "etag": "W/\"19b18-185f4279dbb\"" } }, "responseTime": 63, "msg": "request completed" }, { "level": "info", "time": "2023-01-27T18:00:36.871Z", "req": { "id": 56, "method": "GET", "url": "/icons/search.svg", "query": {}, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "if-none-match": "W/\"3f7-180858b48a7\"", "if-modified-since": "Mon, 02 May 2022 16:12:19 GMT", "sec-ch-ua-mobile": "?0", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "sec-ch-ua-platform": "\"macOS\"", "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "sec-fetch-site": "same-origin", "sec-fetch-mode": "no-cors", "sec-fetch-dest": "image", "referer": "http://localhost:3005/assets/main.css", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9" }, "remoteAddress": "::1", "remotePort": 56446 }, "res": { "statusCode": 304, "headers": { "x-powered-by": "Express", "x-frame-options": "SAMEORIGIN", "accept-ranges": "bytes", "cache-control": "public, max-age=0", "last-modified": "Mon, 02 May 2022 16:12:19 GMT", "etag": "W/\"3f7-180858b48a7\"" } }, "responseTime": 8, "msg": "request completed" }, [socket] onArticlesRequested, channel id: [REDACTED] { "level": "info", "time": "2023-01-27T18:00:37.152Z", "req": { "id": 57, "method": "GET", "url": "/api/sessions", "query": {}, "params": {}, "headers": { "x-datadog-trace-id": "[REDACTED]", "x-datadog-parent-id": "[REDACTED]", "x-datadog-sampling-priority": "1", "host": "localhost:3005", "accept-encoding": "gzip, deflate", "connection": "close" }, "remoteAddress": "::ffff:127.0.0.1", "remotePort": 56450 }, "res": { "statusCode": 200, "headers": { "x-powered-by": "Express", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "content-length": "2", "etag": "W/\"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w\"", "vary": "Accept-Encoding" } }, "responseTime": 71, "msg": "request errored" }, { "level": "info", "time": "2023-01-27T18:00:37.325Z", "req": { "id": 59, "method": "GET", "url": "/images/favicon.ico", "query": {}, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "sec-ch-ua-mobile": "?0", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "sec-ch-ua-platform": "\"macOS\"", "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "sec-fetch-site": "same-origin", "sec-fetch-mode": "no-cors", "sec-fetch-dest": "image", "referer": "http://localhost:3005/articles", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "if-none-match": "W/\"76cc-Oj2M/jF5AiF2s5NrMFAiMgN13kY\"" }, "remoteAddress": "::1", "remotePort": 56452 }, "res": { "statusCode": 304, "headers": { "x-powered-by": "Express", "x-frame-options": "SAMEORIGIN", "etag": "W/\"76cc-Oj2M/jF5AiF2s5NrMFAiMgN13kY\"" } }, "responseTime": 176, "msg": "request completed" }, { "level": "info", "time": "2023-01-27T18:00:37.777Z", "req": { "id": 58, "method": "GET", "url": "/api/channels?user_id=[REDACTED]&limit=50", "query": { "user_id": "[REDACTED]", "limit": "50" }, "params": {}, "headers": { "host": "localhost:3005", "connection": "keep-alive", "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"", "sec-ch-ua-mobile": "?0", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", "sec-ch-ua-platform": "\"macOS\"", "accept": "*/*", "sec-fetch-site": "same-origin", "sec-fetch-mode": "cors", "sec-fetch-dest": "empty", "referer": "http://localhost:3005/articles", "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "if-none-match": "W/\"568-ZFbZfVT8b6crZwt3rqLB38sA2wE\"" }, "remoteAddress": "::1", "remotePort": 56451 }, "res": { "statusCode": 304, "headers": { "x-powered-by": "Express", "access-control-allow-origin": "*", "etag": "W/\"568-ZFbZfVT8b6crZwt3rqLB38sA2wE\"" } }, "responseTime": 636, "msg": "request errored" } ```