-
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
Remove logger outside of WriteJSONKeys #35920
Conversation
This commit adds a benchmarks for the method WriteJSONKeys Signed-off-by: Alexandros, Sapranidis <[email protected]>
This commit moves the initialization of the logger outside of the method WriteJSONKeys and saves memory allocations. Signed-off-by: Alexandros, Sapranidis <[email protected]>
This pull request doesn't have a |
This pull request does not have a backport label.
To fixup this pull request, you need to add the backport labels for the needed
|
🚀 |
@@ -35,11 +35,11 @@ var ( | |||
// ErrInvalidTimestamp is returned when parsing of a @timestamp field fails. | |||
// Supported formats: ISO8601, RFC3339 | |||
ErrInvalidTimestamp = errors.New("failed to parse @timestamp, unknown format") | |||
logger = logp.NewLogger("jsonhelper") |
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.
Does this logger still work? This becomes an order of initialization problem. The logp package is not yet initialized at this point so you get a no-op logger returned.
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.
When tested in the unit/benchmark tests, it was properly initialized.
I can move this into a func init()
on this package or see if we propagate it as part of the function parameters from the caller.
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.
it was properly initialized.
It will be initialized, but I would argue not properly. Moving it to an init()
will not fix the issue since that still happens before the logp
package receives its configuration through logp.Configure()
. The godoc for NewLogger
calls this out:
// NewLogger returns a new Logger labeled with the name of the selector. This
// should never be used from any global contexts, otherwise you will receive a
// no-op Logger. This is because the logp package needs to be initialized first.
If you apply this diff and run the test again, nothing gets logged.
go test -v -run TestWriteJSONKeys
diff --git a/libbeat/common/jsontransform/jsonhelper.go b/libbeat/common/jsontransform/jsonhelper.go
index 935eac90a7..c1e9a5d05b 100644
--- a/libbeat/common/jsontransform/jsonhelper.go
+++ b/libbeat/common/jsontransform/jsonhelper.go
@@ -40,6 +40,7 @@ var (
// WriteJSONKeys writes the json keys to the given event based on the overwriteKeys option and the addErrKey
func WriteJSONKeys(event *beat.Event, keys map[string]interface{}, expandKeys, overwriteKeys, addErrKey bool) {
+ logger.Error("NEVER SHOWN")
if expandKeys {
if err := expandFields(keys); err != nil {
logger.Errorf("JSON: failed to expand fields: %s", err)
diff --git a/libbeat/common/jsontransform/jsonhelper_test.go b/libbeat/common/jsontransform/jsonhelper_test.go
index d45ca5c3a3..9f43c1dbb3 100644
--- a/libbeat/common/jsontransform/jsonhelper_test.go
+++ b/libbeat/common/jsontransform/jsonhelper_test.go
@@ -24,10 +24,13 @@ import (
"github.com/stretchr/testify/require"
"github.com/elastic/beats/v7/libbeat/beat"
+ "github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/mapstr"
)
func TestWriteJSONKeys(t *testing.T) {
+ logp.TestingSetup()
+
now := time.Now()
now = now.Round(time.Second)
Solutions
- One solution would be to defer initialization of the logger until the time of first use. Like
var (
pkgLogger *logp.Logger
pkgLoggerInitOnce sync.Once
)
func logger() *logp.Logger {
pkgLoggerInitOnce.Do(func() {
pkgLogger = logp.NewLogger("jsontransform")
})
return pkgLogger
}
func WriteJSONKeys(...) {
logger().Errorf("JSON: failed to expand fields: %s", err)
}
- Remove logging from this function. I kind of find it annoying that it does any logging. There is already error handling present and that is via the
addErrKey
feature. As a user, if I care about errors then I should be usingaddErrKey==true
.
This highlights another inefficiency. WhenaddErrKey==false
the code is always executingcreateJSONError(err.Error())
which then goes completely unused.
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 would opt for the solution 2. It makes more sense to not require any logging inside that function and if we need to, we can log in the caller.
The createJSONError(err.Error())
aspect, I noticed as well, but I was not 100% sure the reasoning behind that so I was kind of reluctant to touch in this changeset.
The error is present in the output of the event. The logger here is kind of redundant. Signed-off-by: Alexandros, Sapranidis <[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.
Let's also fix the redundant call to createJSONError
if addErrKey
is false
we can change SetErrorWithOption
to receive a string and call createJSONError
only if addErrKey
is true
. Behavior will stay the same.
This change tryies to simplify the writing of error in an Event. Signed-off-by: Alexandros, Sapranidis <[email protected]>
Updated the function SetErrorWithOption in order to accomodate the addition of the data and field which is something that it was used in the processors.json_fields Signed-off-by: Alexandros, Sapranidis <[email protected]>
Signed-off-by: Alexandros, Sapranidis <[email protected]>
Signed-off-by: Alexandros, Sapranidis <[email protected]>
Signed-off-by: Alexandros, Sapranidis <[email protected]>
Signed-off-by: Alexandros, Sapranidis <[email protected]>
Signed-off-by: Alexandros, Sapranidis <[email protected]>
libbeat/beat/event.go
Outdated
e.Fields["error"] = jsonErr | ||
errorField := mapstr.M{"message": message, "type": "json"} | ||
if data != "" { | ||
_, _ = errorField.Put("data", data) |
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.
_, _ = errorField.Put("data", data) | |
errorField["data"] = data |
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.
But upon closer inspection, I think we should not add these two fields into the error
object because they are not part of ECS error. Perhaps find a way to incorporate them into the error.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 just tried to keep compatibility with the current working code from
If we need to change this, we might want to do it as a followup work outside of the work on this PR, WDYT?
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 agree. I missed that they were already present.
Co-authored-by: Andrew Kroh <[email protected]>
Co-authored-by: Andrew Kroh <[email protected]>
Co-authored-by: Andrew Kroh <[email protected]>
Co-authored-by: Andrew Kroh <[email protected]>
@alexsapran could you please move this over the line? I would happy to make it land as soon as possible. |
Signed-off-by: Alexandros, Sapranidis <[email protected]>
This commit removes the logger from the WriteJSONKeys which is executed as part of the hot path of the Event and was allocating a new logger for each event. This has an impact on the memory allocation of the function and because it's executed for each event, we see a direct benefit in the overall memory allocations.
What does this PR do?
This change is removing the creation of the logger object inside of the WriteJSONKeys method.
That method is executed for each event causing the logger to initialize objects for each event.
Additionally adding a benchmark that show the impact of the change, for a specific scenario.
Signed-off-by: Alexandros, Sapranidis [email protected]
Why is it important?
Under certain conditions for Filebeat, but not only, but the logger was also consuming overall a lot of memory. That memory then had to be reclaimed by the GC, so reducing the logger memory, actually reduces the gc work.
Checklist
- [ ] I have added an entry inCHANGELOG.next.asciidoc
orCHANGELOG-developer.next.asciidoc
.How to test this PR locally
logp.NewLogger