-
-
Notifications
You must be signed in to change notification settings - Fork 212
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
Rework Logger API #682
Rework Logger API #682
Conversation
zerolog is optimized for logging and does not allocate memory unlike fmr.Sprintf() for debug logs Signed-off-by: Manoj Gopalakrishnan <manoj.gopalakrishnan@intel.com>
1a585bd
to
0f8ae9a
Compare
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## v3/dev #682 +/- ##
==========================================
+ Coverage 80.57% 80.85% +0.27%
==========================================
Files 144 146 +2
Lines 7763 7986 +223
==========================================
+ Hits 6255 6457 +202
- Misses 1278 1303 +25
+ Partials 230 226 -4
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
@@ -170,12 +199,18 @@ func (a *ctlFn) Evaluate(_ rules.RuleMetadata, txS rules.TransactionState) { | |||
case ctlHashEnforcement: | |||
// Not supported yet | |||
case ctlDebugLogLevel: |
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 was a good way to try out or API. Turned out to work.
@@ -186,6 +188,9 @@ type Transaction interface { | |||
// MatchedRules returns the rules that have matched the requests with associated information. | |||
MatchedRules() []MatchedRule | |||
|
|||
// DebugLogger returns the debug logger for this transaction. | |||
DebugLogger() debuglogger.Logger |
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.
Adding this allows us to centralize logs in connectors and also be in sync with the changes made through WAF directives (otherwise if we pass a logger and the output or the level is changed inside waf due to immutability we don't keep track of that in the provided log).
Uint(key string, i uint) Event | ||
// Stringer adds the field key with val.String() (or null if val is nil) | ||
// to the Event. | ||
Stringer(key string, val fmt.Stringer) Event |
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 may be useful to have a way to add an entire dictionary. Not saying we should implement it right now, but it may be good to have that in the interface.
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 defer this until the point we need it. Still it will be a breaking change but adding a dict sounds very specific.
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 was thinking of ways to log an entire object or some map/slice field within an object, instead of having to do it for each integer, etc. But, I guess, we can instead serialize the object to JSON with Marshall() and then log that JSON string.
So I agree we can drop or punt this.
internal/corazawaf/rule.go
Outdated
tx.WAF.Logger.Debug("[%s] [%d] Evaluating rule %d", tx.id, rid, r.ID_) | ||
defer tx.WAF.Logger.Debug("[%s] [%d] Finish evaluating rule %d", tx.id, rid, r.ID_) | ||
tx.DebugLogger().Debug().Str("tx_id", tx.id).Int("rule_id", rid).Msg("Evaluating rule") | ||
defer tx.DebugLogger().Debug().Str("tx_id", tx.id).Int("rule_id", rid).Msg("Finish evaluating rule") |
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 would be good to check if golang does common sub-expression elimination to evaluate the common parts just once. The docs don't mention it. I suspect this is a hot path, so it may be worth it.
PTAL @anuraaga @ns-sundar @manojgop |
@anuraaga @ns-sundar @manojgop you can see the new logger API in action here: corazawaf/coraza-proxy-wasm#160 |
Logger is immutable by design, mainly because that allow us to pass logger
among layers with enriched context (for example, the logger we create at
WAF then is passed down to the transaction with the tx_id, if we do mutate
the context then all logs in the transaction will carry a rule ID which is
incorrect. I think in this case we can roll back the change and don't
create a new logger, just pass the rule_id every time inside the method.
…On Sat, 4 Mar 2023, 05:49 manojgop, ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In internal/corazawaf/rule.go
<#682 (comment)>:
> @@ -174,10 +175,12 @@ func (r *Rule) doEvaluate(phase types.RulePhase, tx *Transaction, cache map[tran
rid = r.ParentID_
}
+ logger := tx.DebugLogger().With(debuglogger.Int("rule_id", rid))
Creating logger instance here is resulting in additional heap allocations
and is impacting performance. Can we just update the context with new
"rule_id" instead of creating new logger instance
—
Reply to this email directly, view it on GitHub
<#682 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAXOYAVBNAP67LKBYJ6OTWDW2LCUTANCNFSM6AAAAAAVNDNZGI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
In that case , would be better to rollback this change for rule id. |
@manojgop please do re-check and let me know if you are happy in terms of allocations so I can finally merge this PR. |
Performance looks good now after rollback. Just FYI - In my system creating the new logger instance resulted in 30% reduction in performance when I ran testing/coreruleset bench mark. I think it might be good to add some perf tests as part of GitHub Action CI, so that it'll be easy to capture performance regression (in a different PR) |
Before Rollback (creating new logger instance for every rule id) |
I think it might be good to add some perf tests as part of GitHub Action
CI, so that it'll be easy to capture performance regression (in a different
PR)
@manojgop I think we have that but maybe not working properly
https://github.com/corazawaf/coraza/blob/v3/dev/.github/workflows/benchmark.yml#L36
Also I think it mixes results among PRs, anyways would you be up to
introduce this checks on CI?
…On Sat, 4 Mar 2023, 06:37 manojgop, ***@***.***> wrote:
***@***.**** approved this pull request.
—
Reply to this email directly, view it on GitHub
<#682 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAXOYAXINKUELQ2LDJORAKLW2LIH3ANCNFSM6AAAAAAVNDNZGI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
I know this is merged, but it may be worthwhile to document some additional data points on how far the allocations get reduced with 'zerolog'. Environment: IceLake VM with 4 vCPUs, 6 GB RAM
The data shows a consistent large reduction in allocations, thus validating the premise behind moving to zerolog. |
Thanks for the great summary @ns-sundar |
* Use zerolog for logging. zerolog is optimized for logging and does not allocate memory unlike fmr.Sprintf() for debug logs Signed-off-by: Manoj Gopalakrishnan <manoj.gopalakrishnan@intel.com> * chore: introduce API changes to ease support of zerolog. * chore: uses interface of logging. * chore: uniformize logger messages. * feat: polish debug logger API. * chore: small nit in nop event. * chore: uniformize log fields. * docs: explains the timestamp skip. * chore: improves nop loggic and also print allocations. * chore: fixes missing log messages. * chore: generic improvements. * tests: improves coverage. * chore: readds log. * tests: improves coverage. * feat: adds logger per transaction to allow 'ctlDebugLogLevel'. * chore: nit printf. * tests: covers 'ctlDebugLogLevel'. * feat: adds Logger.With context fields as per @ns-sundar suggestion. * chore: removes Event.Errs method to narrow down the API surface. * docs: adds more comments on the IsEnabled method. * chore: uses contextful logs for rule. * feat: adds PrinterFactory abstraction to ease the plug of new logs. * chore: refine printer. * chore: rollsback creating a new log per rule evaluation. --------- Signed-off-by: Manoj Gopalakrishnan <manoj.gopalakrishnan@intel.com> Co-authored-by: Manoj Gopalakrishnan <manoj.gopalakrishnan@intel.com>
This PR follows this PR manojgop#3 and conflates some of the efforts from @manojgop, @ns-sundar and me around reducing allocations in logging in the context of the @intel's research https://owasp.slack.com/archives/C02BXH135AT/p1677616370248079