Skip to content
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

#1744 Avoid calls to 'Logger.Log' if LogLevel not enabled in appsettings.json #1745

Conversation

ggnaegi
Copy link
Member

@ggnaegi ggnaegi commented Oct 18, 2023

Closes #1744

Changing string parameter of IOcelotLogger methods to Func<string>, modifying AspDotNetLogger.cs, only one main method and verifying if LogLevel is enabled. If log level isn't enabled, then return.

Proposed Changes

  • Using Func<string> instead of string as parameter for log methods, avoiding unneeded string operations
  • Checking if the LogLevel is enabled before 1) Calling ILogger.Log method; 2) calling Func<string>.Invoke().
  • Code refactoring, only one method for Log writing in AspDotNetLogger.cs
private void WriteLog(LogLevel logLevel, Func<string> messageFactory, Exception exception = null)
{
    if (!_logger.IsEnabled(logLevel))
    {
        return;
    }

    var requestId = GetOcelotRequestId();
    var previousRequestId = GetOcelotPreviousRequestId();

    var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {messageFactory.Invoke()}";

    _logger.Log(logLevel, default, state, exception, _func);
}

Benchmarks:

@raman-m @RaynaldM
Ok, after the refactoring, I realized that the benchmark, per design, has no log level defined. If I change the condition to

if (_logger.IsEnabled(logLevel))
        {
            throw new Exception("min si c'est génial");
        }

then it will run without throwing exceptions. It means IsEnabled is never true there. Ok, since I know that, and I have a wonderful unique wrapper method, I can get the the benchmarks values nearly without any logs activities.
image
Figure 1: Benchmark with empty WriteLog Wrapper method

Now, let's put back the new WriteLog method implementation. Performance is not as good as no logs activities at all, but the performance is still great.
image
Figure 2: Benchmark with new WriteLog Wrapper method

We can now try to log everything - at least call the log method
image
Figure 3: Log everything

And a final check, with the current develop branch
image
Figure 4: Current develop branch benchmark

As you can see, we have similar results for 3 and 4.

Discussion

@ggnaegi ggnaegi changed the title Logging: Avoiding calls to Logger.Log if LogLevel not enabled & instead of a string param use Func<string> #1736 Logging: Avoiding calls to Logger.Log if LogLevel not enabled & instead of a string param use Func<string> Oct 18, 2023
@ggnaegi ggnaegi changed the title #1736 Logging: Avoiding calls to Logger.Log if LogLevel not enabled & instead of a string param use Func<string> #1744 Logging: Avoiding calls to Logger.Log if LogLevel not enabled & instead of a string param use Func<string> Oct 19, 2023
@raman-m raman-m changed the title #1744 Logging: Avoiding calls to Logger.Log if LogLevel not enabled & instead of a string param use Func<string> #1744 Avoid calls to 'Logger.Log' if LogLevel not enabled in appsettings.json Oct 19, 2023
Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not approve this time. Where are the tests?
My concerns:

  • Removing old signature methods is wrong until we'll find a solution to recognize string constants and string building
  • No applied fix by @RaynaldM using #if DEBUG directive, which is main goal
  • No unit tests for refactored WriteLog method, and there are no acceptance tests for the feature which fixes the case when LogLevel isn't enabled in appsettings.json

src/Ocelot/Logging/AspDotNetLogger.cs Outdated Show resolved Hide resolved
src/Ocelot/Logging/IOcelotLogger.cs Outdated Show resolved Hide resolved
src/Ocelot/Logging/AspDotNetLogger.cs Outdated Show resolved Hide resolved
src/Ocelot/Logging/AspDotNetLogger.cs Outdated Show resolved Hide resolved
src/Ocelot/Logging/AspDotNetLogger.cs Outdated Show resolved Hide resolved
test/Ocelot.AcceptanceTests/Steps.cs Outdated Show resolved Hide resolved
@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 19, 2023

I do not approve this time. Where are the tests? My concerns:

  • Removing old signature methods is wrong until we'll find a solution to recognize string constants and string building
  • No applied fix by @RaynaldM using #if DEBUG directive, which is main goal

We can keep the old signature methods, you're right, if it's a string constant, the factory is useless. We would aswell keep the backward compatibility.

@raman-m
Copy link
Member

raman-m commented Oct 19, 2023

Gui,
Could you explain me Benchmarks results please?
Do we need to compare Median values, right?
I see that Ray's approach improves performance decreasing value by ~200 nanoseconds, from 1300 down to 1000.
But your design approach decreased the value in 2+ times, down to ~550 nanoseconds from ~1300 nanoseconds.
This is the perfect result! 🎉 Strong argument to use factory methods! 👍 😍

@raman-m raman-m added proposal Proposal for a new functionality in Ocelot needs feedback Issue is waiting on feedback before acceptance labels Oct 19, 2023
@raman-m
Copy link
Member

raman-m commented Oct 19, 2023

From screenshots I didn't get it what benchmarks did you run?
Have you prepared special benchmark classes or used old ones?
How to run benchmarks locally?

@raman-m
Copy link
Member

raman-m commented Oct 19, 2023

Oh, and I've missed one thing in code review... You haven't tested the case when LogLevel is unknown to prove that optimization and the feature works in real, am I wrong?
We need to write a few acceptance tests... Adding this point to code review results...

@raman-m
Copy link
Member

raman-m commented Oct 19, 2023

@ggnaegi Gui, let me focus on minor release for documentation... I've reviewed this PR, and I'll get back to you after the docs release... So, I'll be silent from now...

@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 19, 2023

Oh, and I've missed one thing in code review... You haven't tested the case when LogLevel is unknown to prove that optimization and the feature works in real, am I wrong? We need to write a few acceptance tests... Adding this point to code review results...

Yes, I will add the test cases.

@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 19, 2023

Oh, and I've missed one thing in code review... You haven't tested the case when LogLevel is unknown to prove that optimization and the feature works in real, am I wrong? We need to write a few acceptance tests... Adding this point to code review results...

Same tests as @RaynaldM, you can start them locally from test/Ocelot.Benchmarks. I will provide a new Benchmark for the request mapper. It's on going...

@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 27, 2023

@raman-m I think, the code is now ready for review, I have added several unit tests - verifying if invoke is called, verifying if log has been called - and acceptance tests - verifying that the log level corresponds to the appsettings.json -

Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long code requires more improvement.
Thank you for writing tests! I will review maybe later. Try to compress them and use DRY approach: more small helpers.

And I will run benchmarks later too...
I have a concern about benchmarks: Why do you test Serilog injected implementation? In my opinion, we need to test standard MS ASP.NET logger implementations first.

src/Ocelot/Claims/Middleware/ClaimsToClaimsMiddleware.cs Outdated Show resolved Hide resolved
src/Ocelot/Claims/Middleware/ClaimsToClaimsMiddleware.cs Outdated Show resolved Hide resolved
src/Ocelot/Logging/AspDotNetLogger.cs Outdated Show resolved Hide resolved
test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj Outdated Show resolved Hide resolved
test/Ocelot.AcceptanceTests/LogLevelTests.cs Outdated Show resolved Hide resolved
test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj Outdated Show resolved Hide resolved
@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 28, 2023

Long code requires more improvement.
Thank you for writing tests! I will review maybe later. Try to compress them and use DRY approach: more small helpers.

And I will run benchmarks later too...
I have a concern about benchmarks: Why do you test Serilog injected implementation? In my opinion, we need to test standard MS ASP.NET logger implementations first.

It's the case in the unit tests. I'm using serilog in the acceptance tests. I could have created an In memory logger though...

@raman-m
Copy link
Member

raman-m commented Oct 28, 2023

@ggnaegi commented on Oct 28

Could we run tests for different loggers like Microsoft, Serilog etc.?

@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 28, 2023

@ggnaegi commented on Oct 28

Could we run tests for different loggers like Microsoft, Serilog etc.?

Yes, but that's again quite a bit of work...

@ggnaegi ggnaegi requested a review from raman-m October 28, 2023 20:45
@ggnaegi
Copy link
Member Author

ggnaegi commented Oct 28, 2023

@raman-m changes analyzed and code updated. You can re-review

@raman-m
Copy link
Member

raman-m commented Oct 30, 2023

This feature should be included in October's release.
Going to review once again...

@raman-m
Copy link
Member

raman-m commented Nov 1, 2023

@ggnaegi Please, check auto-merge results after the last merging of develop!

@ggnaegi
Copy link
Member Author

ggnaegi commented Nov 1, 2023

Hello @raman-m, should be fine

Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review, 2nd round is over! ✔️

Before fixing issues, it is better to rebase feature branch onto develop.
Sometimes I saw strange diff without actual changes. Maybe they appear after my merging of develop in f1f43bc by GitHub auto-merger. Sorry! Such huge PRs should be rebased each time.

Thanks for the great code quality! 💪

test/Ocelot.AcceptanceTests/Steps.cs Show resolved Hide resolved
test/Ocelot.Benchmarks/LoggingBenchmarks.cs Outdated Show resolved Hide resolved
test/Ocelot.Benchmarks/LoggingBenchmarks.cs Outdated Show resolved Hide resolved
test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj Outdated Show resolved Hide resolved
@raman-m
Copy link
Member

raman-m commented Nov 2, 2023

Could you rebase the feature branch onto ThreeMammals:develop please?
OR
Could you sync your fork to update develop please?
And, rebase the feature branch onto develop please.

@ggnaegi ggnaegi force-pushed the features/1744_a_lot_of_useless_log_debug_in_ocelot branch from 79f79ac to 5283257 Compare November 23, 2023 07:43
@ggnaegi
Copy link
Member Author

ggnaegi commented Nov 23, 2023

@raman-m Rebase done

Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready for delivery! ✅

Congrats, @ggnaegi ! 🥳

@raman-m raman-m added accepted Bug or feature would be accepted as a PR or is being worked on and removed needs feedback Issue is waiting on feedback before acceptance labels Nov 24, 2023
@raman-m raman-m merged commit 388ebc3 into ThreeMammals:develop Nov 24, 2023
@raman-m raman-m mentioned this pull request Nov 24, 2023
raman-m added a commit that referenced this pull request Nov 28, 2023
* #1712 Bump to Polly 8.0 (#1714)

* #1712 Migrate to Polly 8.0

* code review post merge

* post PR

* #1712 Migrate to Polly 8.0

* code review post merge

* Update src/Ocelot.Provider.Polly/PollyQoSProvider.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* namespaces

* Refactor QoS provider

* Refactor AddPolly extension

* Remove single quote because semicolon ends sentence

---------

Co-authored-by: Ray <rmessie@traceparts.com>
Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Cache by header value: a new Header property in (File)CacheOptions configuration of a route (#1172)

@EngRajabi, Mohsen Rajabi (7):
      add header to file cache option
      fix private set
      fix
      <none>
      <none>
      fix build fail
      fix: fix review comment. add unit test for change

@raman-m, Raman Maksimchuk (1):
      Update caching.rst

@raman-m (7):
      Fix errors
      Fix errors
      Fix styling warnings
      Refactor tests
      Add Delimiter
      Refactor generator
      Add unit tests

* Find available port in integration tests (#1173)

* use random ports in integration tests

* Remove and Sort Usings

* Code modern look

* code review

* code review: fix messages

* code review: fix some messages

* code review: Use simple `using` statement

* Add Ocelot.Testing project

---------

Co-authored-by: raman-m <dotnet044@gmail.com>

* #952 #1174 Merge query strings without duplicate values (#1182)

* Fix issue  #952 and #1174

* Fix compiling errors

* Fix warnings

* Fix errors

* Remove and Sort Usings

* CA1845 Use span-based 'string.Concat' and 'AsSpan' instead of 'Substring'.
Use 'AsSpan' with 'string.Concat'

* IDE1006 Naming rule violation: These words must begin with upper case characters: {should_*}.
Fix name violation

* Add namespace

* Fix build errors

* Test class should match the name of tested class

* Simplify too long class names, and they should match

* Move to the parent folder which was empty

* Fix warnings

* Process dictionaries using LINQ to Objects approach

* Fix code review issues from @RaynaldM

* Remove tiny private helper with one reference

* Fix warning & messages

* Define theory instead of 2 facts

* Add unit test for issue #952

* Add additional unit test for #952 to keep param

* Add tests for issue #1174

* Remove unnecessary parameter

* Copy routing.rst from released version

* Refactor the middleware body for query params

* Update routing.rst: Describe query string user scenarios

---------

Co-authored-by: Stjepan Majdak <stjepan.majdak@a1.hr>
Co-authored-by: raman-m <dotnet044@gmail.com>

* #1550 #1706 Addressing the QoS options ExceptionsAllowedBeforeBreaking issue (#1753)

* When using the QoS option "ExceptionsAllowedBeforeBreaking" the circuit breaker never opens the circuit.

* merge issue, PortFinder

* some code improvements, using httpresponsemessage status codes as a base for circuit breaker

* Adding more unit tests, and trying to mitigate the test issues with the method "GivenThereIsAPossiblyBrokenServiceRunningOn"

* fixing some test issues

* setting timeout value to 5000 to avoid side effects

* again timing issues

* timing issues again

* ok, first one ok

* Revert "ok, first one ok"

This reverts commit 2e4a673.

* inline method

* putting back logging for http request exception

* removing logger configuration, back to default

* adding a bit more tests to check the policy wrap

* Removing TimeoutStrategy from parameters, it's set by default to pessimistic, at least one policy will be returned, so using First() in circuit breaker and removing the branch Policy == null from delegating handler.

* Fix StyleCop warnings

* Format parameters

* Sort usings

* since we might have two policies wrapped,  timeout and circuit breaker, we can't use the name CircuitBreaker for polly qos provider, it's not right. Using PollyPolicyWrapper and AsnycPollyPolicy instead.

* modifying circuit breaker delegating handler name, usin Polly policies instead

* renaming CircuitBreakerFactory to PolicyWrapperFactory in tests

* DRY for FileConfiguration, using FileConfigurationFactory

* Add copy constructor

* Refactor setup

* Use expression body for method

* Fix acceptance test

* IDE1006 Naming rule violation: These words must begin with upper case characters

* CA1816 Change ReturnsErrorTests.Dispose() to call GC.SuppressFinalize(object)

* Sort usings

* Use expression body for method

* Return back named arguments

---------

Co-authored-by: raman-m <dotnet044@gmail.com>

* #1179 Add missing documentation for Secured WebSocket #1180

* Add "WebSocket Secure" and "SSL Errors" sections (#1180)

Co-authored-by: raman-m <dotnet044@gmail.com>

* Resolve issues with projects after auto-merging. Format Document

* #1744 Avoid calls to 'Logger.Log' if LogLevel not enabled in appsettings.json (#1745)

* changing string parameter for IOcelotLogger function to Func<string>, modifying asp dot net logger, only one main method and verifying if LogLevel is enabled. If log level isn't enabled, then return.

    pick 847dac7 changing string parameter for IOcelotLogger function to Func<string>, modifying asp dot net logger, only one main method and verifying if LogLevel is enabled. If log level isn't enabled, then return.
    pick d7a8397 adding back the logger methods with string as parameter, avoiding calling the factory when plain string are used.
    pick d413201 simplify method calls

* adding back the logger methods with string as parameter, avoiding calling the factory when plain string are used.

* simplify method calls

* adding unit test case, If minimum log level not set then no logs are written

* adding logging benchmark

* code cleanup in steps and naming issues fixes

   pick c4f6dc9 adding loglevel acceptance tests, verifying that the logs are returned according to the minimum log level set in appsettings
   pick 478f139 enhanced unit tests, verifying 1) that the log method is only called when log level enabled 2) that the string function is only invoked when log level enabled

* adding loglevel acceptance tests, verifying that the logs are returned according to the minimum log level set in appsettings

* enhanced unit tests, verifying 1) that the log method is only called when log level enabled 2) that the string function is only invoked when log level enabled

* weird issue with the merge.

* adding comment

* Update src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update src/Ocelot/Claims/Middleware/ClaimsToClaimsMiddleware.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteProviderFactory.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update src/Ocelot/Logging/AspDotNetLogger.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update test/Ocelot.AcceptanceTests/LogLevelTests.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* Update src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* As mentioned, using OcelotLogger instead of AspDotNeLogger as default logger name

* Some code refactoring and usage of factories in LogLevelTests

* Update src/Ocelot/Claims/Middleware/ClaimsToClaimsMiddleware.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* using overrided method WriteLog for strings, some changes as requested,

* code changes after review 2

    pick ad0e060 Update test/Ocelot.UnitTests/Middleware/OcelotPiplineBuilderTests.cs

* checking test cases

* adding ms logger benchmarks with console provider. Unfortunately, benchmark.net doesn't support "quiet" mode yet.

* 2 small adjustments

* Adding multi targets support for serilog

* Fix warnings

* Review new logger

* Fix unit tests

* The last change but not least

* Update logging.rst: Add draft

* Update logging.rst: Add RequestId section

* Update logging.rst: "Best Practices" section

* Update logging.rst: "Top Logging Performance?" subsection

* Update logging.rst: Rewrite "Request ID" section

* Update requestid.rst: Review and up to date

* Update logging.rst: "Run Benchmarks" section

---------

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* #1783 Less logs for circuit breakers (Polly exceptions) (#1786)

* #1783 More accurate logs for circuit breakers (and other "polly" exceptions)
Remove try/catch in PollyPoliciesDelegatingHandler and add a more generic AddPolly<T> to be able to use a specific PollyQoSProvider

* fix should_be_invalid_re_route_using_downstream_http_version UT

* fix remarks on PR

* arrange code

* fix UT

* merge with release/net8 branch

* switch benchmark to Net8

* Fix warnings

* Final review

---------

Co-authored-by: Ray <rmessie@traceparts.com>
Co-authored-by: raman-m <dotnet044@gmail.com>

* Revert #1172 feature (#1807)

* Revert #1172

* Remove Header

* Take actual version of caching.rst and remove Header info

* Release 22.0 | +semver: breaking

---------

Co-authored-by: Raynald Messié <redbird_project@yahoo.fr>
Co-authored-by: Ray <rmessie@traceparts.com>
Co-authored-by: Mohsen Rajabi <m.kabir8895@gmail.com>
Co-authored-by: jlukawska <56401969+jlukawska@users.noreply.github.com>
Co-authored-by: Stjepan <majdak.stjepan@gmail.com>
Co-authored-by: Stjepan Majdak <stjepan.majdak@a1.hr>
Co-authored-by: Guillaume Gnaegi <58469901+ggnaegi@users.noreply.github.com>
Co-authored-by: Samuel Poirier <sam9291p@gmail.com>
@raman-m raman-m mentioned this pull request Nov 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted Bug or feature would be accepted as a PR or is being worked on proposal Proposal for a new functionality in Ocelot
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A lot of useless log.Debug in Ocelot
3 participants