-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
x-pack/filebeat/input/httpjson: add transaction tracer #32412
Conversation
Pinging @elastic/security-external-integrations (Team:Security-External Integrations) |
/test |
@@ -12,6 +12,8 @@ import ( | |||
"strings" | |||
"time" | |||
|
|||
"gopkg.in/natefinch/lumberjack.v2" |
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 already have a logging library in Beats: https://github.com/elastic/elastic-agent-libs/tree/main/logp that uses go.uber.org/zap under the hood.
If possible I'd prefer to stick with those ones (preferably elastic-agent-libs/logp
) to avoid introducing a new dependency and "logging" library.
What are the advantages of using lumberjack over the ones we already have in Beats?
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.
Another alternative is https://pkg.go.dev/github.com/elastic/elastic-agent-libs/file#Rotator. It gives you an io.WriteCloser
interface and manages rolling the underlying files.
But it looks like the library got polluted since I last looked with a hardcoded file extension 😢 . https://github.com/elastic/elastic-agent-libs/blob/a09d65fd12dec3efe53c44f05562431f96b1028b/file/rotator.go#L416 IMO is should have used filepath.Ext
to get the extension from the configured filename
.
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.
What are the advantages of using lumberjack over the ones we already have in Beats?
Simplicity; this does exactly what is needed and is transparently simple.
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.
@andrewkroh's suggestion looks great and simple. The file extension is a pitty, but we can easily fix that as well. I glanced over the code and it seems to be possible to make the extension configurable without changing the public API.
This pull request is now in conflicts. Could you fix it? 🙏
|
Failure is unrelated. It appears to have come in with https://beats-ci.elastic.co/blue/organizations/jenkins/Beats%2Fbeats/detail/main/666/pipeline. Which does touch code that could explain it — it shows up first then — though I don't know enough about that part of libbeat to be confident of that and it passed the build at the time of the PR. @belimawr Do you think that could be the reason? |
I'll take a look at it right now. |
@efd6, yes, there is a bug on my bugfix 🤣 I'm writing the fix-fix PR right now. Another race condition. Thanks a lot for spotting that!!! |
This pull request is now in conflicts. Could you fix it? 🙏
|
This pull request is now in conflicts. Could you fix it? 🙏
|
Something is not working as expected. I'm not seeing any requests logged.
@@ -42,6 +47,7 @@ func (c *httpClient) do(stdCtx context.Context, req *http.Request) (*http.Respon | |||
return nil, fmt.Errorf("failed to execute http client.Do: %w", err) | |||
} | |||
defer resp.Body.Close() | |||
c.tracer.trace(req, resp) |
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.
I think the request might need to be dumped before it is executed in order to access the body before it is drained.
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.
If you add this and run the tests you will see a log file with the request and response logging in "test.log".
diff --git a/x-pack/filebeat/input/httpjson/input_test.go b/x-pack/filebeat/input/httpjson/input_test.go
index 69617d82a5..d48f8d5ceb 100644
--- a/x-pack/filebeat/input/httpjson/input_test.go
+++ b/x-pack/filebeat/input/httpjson/input_test.go
@@ -583,6 +583,7 @@ func TestInput(t *testing.T) {
for _, testCase := range testCases {
tc := testCase
t.Run(tc.name, func(t *testing.T) {
+ tc.baseConfig["request.tracer.filename"] = "test.log"
tc.setupServer(t, tc.handler, tc.baseConfig)
cfg := conf.MustNewConfigFrom(tc.baseConfig)
No body though, that will need to be fixed.
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.
I'm testing against a mock server that responds with an HTTP 503 in a particular case. When this happens the tracer logs "no response (2022/07/25 11:28:46 no response 1658762511476.5
).
One idea I had was too see if there is a different hook point such that we could implement a http.RoundTripper for capturing the request/response. I think this could also give us visibility into requests made by retryablehttp... 🤔
That is possible though it adds a fair bit of complexity/indirection. I've fixed the loss of non-erroring non-200 status logging. |
I think the complexity is not too bad. I had to see for myself (it's just a hack), but have a look at 93d5f2e which builds upon your change and uses the In my hack I did choose a structured logger. I figured if I get a big trace log from a user that I'm trying to help, then this format will be easier to analyze in Elasticsearch. One feature that I thought would be nice to have is a |
That's approximately the level of complexity that I was thinking it would involve when you include the code in go-examples. I agree that if the intention is for looking at large dumps then a structured logger would be better. Are you happy for me to pull the code you have in go-examples into beats? One comment on the httplog, the logging of the body is not currently ECS compliant since it dumps the complete serialised request, not the body (same for the response). To fix this we'd drop the use of httputil and just make a local drainBody to get those bytes. WDYT? |
Yeah, you are welcome to pull in any of that code. I did realize that I was including more than what is expected in those ECS |
The helper is tiny so I'll make use of a proverb. |
… req/resp logging Co-authored-by: Andrew Kroh <andrew.kroh@elastic.co>
Initially in an internal package in httpjson, but I can imagine that this will have general utility, so it can be moved out later when needed elsewhere. |
E2E test failure is unrelated. |
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.
Thanks for making it ECS compliant.
return rt.txBaseID + "-" + strconv.FormatUint(count, 10) | ||
} | ||
|
||
var noResponse = zap.NamedError("error.message", errors.New("unexpected nil response")) |
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.
Have you checked the output of this? I wanted to make sure that it behaves as expected because I recall that ecszap automatically takes regular zap.Error()
calls and writes them to error.message
and wanted to make sure this did not result in an extra message
like error.message.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.
I will check.
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 two types of error messages:
{"log.level":"debug","@timestamp":"2022-07-28T21:08:54.725+0930","message":"HTTP request","transaction.id":"63GBEPIAVC2HE-1","url.original":"http://127.0.0.1:57587","url.scheme":"http","url.path":"","url.domain":"127.0.0.1","url.port":"57587","url.query":"","http.request.method":"POST","user_agent.original":"Elastic-Filebeat/8.4.0 (darwin; amd64; unknown; 0001-01-01 00:00:00 +0000 UTC)","error.message":[{"error":"failed to read request body: faux"},{"error":"failed to dump request: faux"}],"ecs.version":"1.6.0"}
and
{"log.level":"debug","@timestamp":"2022-07-28T21:12:09.042+0930","message":"HTTP response error","transaction.id":"R3VDV93NVC2HE-1","error":{"message":"unexpected nil response"},"ecs.version":"1.6.0"}
So the noResponse
error looks like it is working as intended. I'll fix the other.
New version:
Single
{"log.level":"debug","@timestamp":"2022-07-28T21:24:05.124+0930","message":"HTTP request","transaction.id":"N34CJAOTVG2HE-3","url.original":"http://127.0.0.1:59402","url.scheme":"http","url.path":"","url.domain":"127.0.0.1","url.port":"59402","url.query":"","http.request.method":"GET","user_agent.original":"Elastic-Filebeat/8.4.0 (darwin; amd64; unknown; 0001-01-01 00:00:00 +0000 UTC)","event.original":"GET / HTTP/1.1\r\nHost: 127.0.0.1:59402\r\nUser-Agent: Elastic-Filebeat/8.4.0 (darwin; amd64; unknown; 0001-01-01 00:00:00 +0000 UTC)\r\nAccept: application/json\r\nAccept-Encoding: gzip\r\n\r\n","error.message":"failed to read request body: faux","ecs.version":"1.6.0"}
Double
{"log.level":"debug","@timestamp":"2022-07-28T21:24:02.121+0930","message":"HTTP request","transaction.id":"F31B1AOTVG2HE-2","url.original":"http://127.0.0.1:59398","url.scheme":"http","url.path":"","url.domain":"127.0.0.1","url.port":"59398","url.query":"","http.request.method":"GET","user_agent.original":"Elastic-Filebeat/8.4.0 (darwin; amd64; unknown; 0001-01-01 00:00:00 +0000 UTC)","error.message":["failed to read request body: faux","failed to dump request: faux"],"ecs.version":"1.6.0"}
Round trip
{"log.level":"debug","@timestamp":"2022-07-28T21:24:03.123+0930","message":"HTTP response error","transaction.id":"N34CJAOTVG2HE-2","error":{"message":"unexpected nil response"},"ecs.version":"1.6.0"}
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.
"New version" looks good.
x-pack/filebeat/input/httpjson/internal/httplog/roundtripper.go
Outdated
Show resolved
Hide resolved
Co-authored-by: Andrew Kroh <andrew.kroh@elastic.co>
What does this PR do?
Why is it important?
Checklist
CHANGELOG.next.asciidoc
orCHANGELOG-developer.next.asciidoc
.Author's Checklist
How to test this PR locally
Related issues
Use cases
Screenshots
Logs