-
Notifications
You must be signed in to change notification settings - Fork 2
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
mrc-5048: Add request ID into logs #38
Conversation
@@ -1,5 +1,6 @@ | |||
porcelain_filters <- function(req, res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These req
, res
args were not being used
@@ -0,0 +1,19 @@ | |||
add <- function(a, b) { | |||
logger <- lgr::get_logger("add.chatty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note how users will have to get the logger if they want to use the request ID (and all other things configured by porcelain). They could also pass this through from when the logger is created in the api
. We could add a function to make this easier.
tests/testthat/test-roxygen.R
Outdated
@@ -99,7 +99,7 @@ test_that("Nice error on parse failure", { | |||
err <- expect_error( | |||
roxygen2::parse_text(text)) | |||
expect_match( | |||
err$message, | |||
err$parent$message, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think this has changed due to porcelain update
So that the request ID is available to logs whilst endpoint is being run
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #38 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 19 19
Lines 975 992 +17
=========================================
+ Hits 975 992 +17 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice. Just some minor points
Co-authored-by: Paul Liétar <[email protected]>
Co-authored-by: Paul Liétar <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, tiny optional comment
Co-authored-by: M-Kusumgar <[email protected]>
R/logging.R
Outdated
@@ -1,3 +1,5 @@ | |||
LOG_FILTER_REQUEST_ID_NAME <- "request_id" # nolint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage of this constant seem reduced by (I'm guessing) it needing to match the name used in FilterInject
. You could use the .list
argument there and do
FilterInject$new(.list = set_names(request_id, LOG_FILTER_REQUEST_ID_NAME))
which would reuse this constant at least
R/filter.R
Outdated
req$REQUEST_ID <- request_id | ||
res$setHeader("x-request-id", request_id) | ||
if (!is.null(logger)) { | ||
logger$add_filter(lgr::FilterInject$new(request_id = request_id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interaction with lgr feels like it's going to have performance issues each time (based on my previous experience with the package). Each request we'll be doing
- add_filter
- FilterInject creation
- remove_filter
I presume this means that when the request comes through we're checking to see "do we have the appropriate header" then if so adding additional data to the log output? Any reason this can't be done directly in porcelain_log_postserialize
where we have req already? It's possible I'm missing something here though.
OTOH, it might be worth looking to see how bad this is performance wise - see if it's actually an issue with a quick benchmark with and without the header being present and see how long a roundtrip takes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We chatted about this in person but just putting this down here for future reference.
We can't just use porcelain_log_postserialize
as we want to add the request ID into the logger so if a user writes a log call in their API impl it will pick up the request ID.
With plumber we have 4 hooks we can use preroute, postroute, preserialize and posterialize. In preroute we don't have a handle on the "HTTP_X_REQUEST_ID" so we need to do this after the preroute, but by actual code endpoint is run before we get to postroute. So we have to handle this in a filter.
I did some benchmarking on this, by running up the API in a background process with the add.chatty
package I added in this PR. There isn't a huge amount of variation in timings
With no filter
rashton@wpia-dide270:~/projects/porcelain$ ./timeit curl -w "@curl_format.txt" -o /dev/null -s "http://localhost:8552/?a=3&b=3"
Average: 0.00569371 N: 1000
With the filter which creates and removes the object every time
rashton@wpia-dide270:~/projects/porcelain$ ./timeit curl -w "@curl_format.txt" -o /dev/null -s "http://localhost:9120/?a=3&b=3"
Average: 0.0055903 N: 1000
With updated filter which just changes the request ID on an the filter object which exists in cache
rashton@wpia-dide270:~/projects/porcelain$ ./timeit curl -w "@curl_format.txt" -o /dev/null -s "http://localhost:9343/?a=3&b=3"
Average: 0.00546013 N: 1000
So very similar average times, less different than I was expecting. Feels nice to not have to create the object every time so have gone with that but previous impl I think read a little more simply so we can always revert back.
@plietar has added request_id into Rust API in this mrc-ide/outpack_server#58, if a request is received with header
x-request-id
it will be included in log messages, if one not sent a request ID will be generated and included in the logs.This PR adds the same pattern so we can use it across all our R APIs. Hopefully with this, if we send a request from Kotlin backend to any of our services we can trace it through with this ID.
This PR will
x-request-id
it will return it in the response header. If one not sent, it will generate a uuid.