Skip to content

Commit

Permalink
Release 22.0 (#1805)
Browse files Browse the repository at this point in the history
* #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 <[email protected]>

* namespaces

* Refactor QoS provider

* Refactor AddPolly extension

* Remove single quote because semicolon ends sentence

---------

Co-authored-by: Ray <[email protected]>
Co-authored-by: Raman Maksimchuk <[email protected]>

* 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 <[email protected]>

* #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 <[email protected]>
Co-authored-by: raman-m <[email protected]>

* #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 <[email protected]>

* #1179 Add missing documentation for Secured WebSocket #1180

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

Co-authored-by: raman-m <[email protected]>

* 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 <[email protected]>

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

Co-authored-by: Raman Maksimchuk <[email protected]>

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

Co-authored-by: Raman Maksimchuk <[email protected]>

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

Co-authored-by: Raman Maksimchuk <[email protected]>

* Update src/Ocelot/Logging/AspDotNetLogger.cs

Co-authored-by: Raman Maksimchuk <[email protected]>

* Update test/Ocelot.AcceptanceTests/LogLevelTests.cs

Co-authored-by: Raman Maksimchuk <[email protected]>

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

Co-authored-by: Raman Maksimchuk <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* #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 <[email protected]>
Co-authored-by: raman-m <[email protected]>

* 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é <[email protected]>
Co-authored-by: Ray <[email protected]>
Co-authored-by: Mohsen Rajabi <[email protected]>
Co-authored-by: jlukawska <[email protected]>
Co-authored-by: Stjepan <[email protected]>
Co-authored-by: Stjepan Majdak <[email protected]>
Co-authored-by: Guillaume Gnaegi <[email protected]>
Co-authored-by: Samuel Poirier <[email protected]>
  • Loading branch information
9 people authored Nov 28, 2023
1 parent 0b25c41 commit d24d5c9
Show file tree
Hide file tree
Showing 150 changed files with 4,362 additions and 2,494 deletions.
7 changes: 7 additions & 0 deletions Ocelot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDisco
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Samples.ServiceDiscovery.DownstreamService", "samples\OcelotServiceDiscovery\DownstreamService\Ocelot.Samples.ServiceDiscovery.DownstreamService.csproj", "{E2AC741A-4120-4D59-B5E4-16382ED45E8D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ocelot.Testing", "test\Ocelot.Testing\Ocelot.Testing.csproj", "{AE6BCCBD-0687-4C58-B30F-4ABBC6422087}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -203,6 +205,10 @@ Global
{E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2AC741A-4120-4D59-B5E4-16382ED45E8D}.Release|Any CPU.Build.0 = Release|Any CPU
{AE6BCCBD-0687-4C58-B30F-4ABBC6422087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE6BCCBD-0687-4C58-B30F-4ABBC6422087}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE6BCCBD-0687-4C58-B30F-4ABBC6422087}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE6BCCBD-0687-4C58-B30F-4ABBC6422087}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -242,6 +248,7 @@ Global
{25C30AAA-12DD-4BA5-A53F-9271E54EBAB7} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C}
{D37209EA-C13E-42AE-B851-A8604F1FCD0E} = {25C30AAA-12DD-4BA5-A53F-9271E54EBAB7}
{E2AC741A-4120-4D59-B5E4-16382ED45E8D} = {25C30AAA-12DD-4BA5-A53F-9271E54EBAB7}
{AE6BCCBD-0687-4C58-B30F-4ABBC6422087} = {5B401523-36DA-4491-B73A-7590A26E420B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}
Expand Down
44 changes: 30 additions & 14 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
## Upgrade to .NET 8 (version {0}) aka [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) release
> Read article: [Announcing .NET 8](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8/) by Gaurav Seth, on November 14th, 2023
## October 2023 (version {0}) aka [Swiss Locomotive](https://en.wikipedia.org/wiki/SBB-CFF-FFS_Ae_6/6) release
> Codenamed as **[Swiss Locomotive](https://www.google.com/search?q=swiss+locomotive)**
### About
We are pleased to announce to you that we can now offer the support of [.NET 8](https://dotnet.microsoft.com/en-us/download).
But that is not all, in this release, we are adopting support of several versions of the .NET framework through [multitargeting](https://learn.microsoft.com/en-us/dotnet/standard/frameworks).
The Ocelot distribution is now compatible with .NET **6**, **7** and **8**. :tada:
### Focused On
<details>
<summary><b>Logging feature</b>. Performance review, redesign and improvements with new best practices to log</summary>

In the future, we will try to ensure the support of the [.NET SDKs](https://dotnet.microsoft.com/en-us/download/dotnet) that are still actively maintained by the .NET team and community.
Current .NET versions in support are the following: [6, 7, 8](https://dotnet.microsoft.com/en-us/download/dotnet).
- Proposing a centralized `WriteLog` method for the `OcelotLogger`
- Factory methods for computed strings such as `string.Format` or interpolated strings
- Using `ILogger.IsEnabled` before calling the native `WriteLog` implementation and invoking string factory method
</details>
<details>
<summary><b>Quality of Service feature</b>. Redesign and stabilization, and it produces less log records now.</summary>

- Fixing issue with [Polly](https://www.thepollyproject.org/) Circuit Breaker not opening after max number of retries reached
- Removing useless log calls that could have an impact on performance
- Polly [lib](https://www.nuget.org/packages/Polly#versions-body-tab) reference updating to latest `8.2.0` with some code improvements
</details>
<details>
<summary>Documentation for <b>Logging</b>, <b>Request ID</b>, <b>Routing</b> and <b>Websockets</b></summary>

- [Logging](https://ocelot.readthedocs.io/en/latest/features/logging.html)
- [Request ID](https://ocelot.readthedocs.io/en/latest/features/requestid.html)
- [Routing](https://ocelot.readthedocs.io/en/latest/features/routing.html)
- [Websockets](https://ocelot.readthedocs.io/en/latest/features/websockets.html)
</details>
<details>
<summary>Testing improvements and stabilization aka <b>bug fixing</b></summary>

### Technical info
As an ASP.NET Core app, now Ocelot targets `net6.0`, `net7.0` and `net8.0` frameworks.

Starting with **v{0}**, the solution's code base supports [Multitargeting](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-multitargeting-overview) as SDK-style projects.
It should be easier for teams to move between (migrate to) .NET 6, 7 and 8 frameworks. Also, new features will be available for all .NET SDKs which we support via multitargeting.
Find out more here: [Target frameworks in SDK-style projects](https://learn.microsoft.com/en-us/dotnet/standard/frameworks)
- [Routing](https://ocelot.readthedocs.io/en/latest/features/routing.html) bug fixing: query string placeholders including **CatchAll** one aka `{{everything}}` and query string duplicates removal
- [QoS](https://ocelot.readthedocs.io/en/latest/features/qualityofservice.html) bug fixing: Polly circuit breaker exceptions
- Testing bug fixing: rare failed builds because of unstable Polly tests. Acceptance common logic for ports
</details>
11 changes: 6 additions & 5 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ Task("CreateReleaseNotes")
var releaseHeader = string.Format(System.IO.File.ReadAllText("./ReleaseNotes.md"), releaseVersion, lastRelease);
releaseNotes = new List<string> { releaseHeader };

var shortlogSummary = GitHelper($"shortlog --no-merges --numbered --summary {lastRelease}..HEAD");
var shortlogSummary = GitHelper($"shortlog --no-merges --numbered --summary {lastRelease}..HEAD")
.ToList();
var re = new Regex(@"^[\s\t]*(?'commits'\d+)[\s\t]+(?'author'.*)$");
var summary = shortlogSummary
.Where(x => re.IsMatch(x))
Expand Down Expand Up @@ -207,7 +208,6 @@ Task("CreateReleaseNotes")
static string HonorForDeletions(string place, string author, int commits, int files, int insertions, int deletions)
=> HonorForInsertions(place, author, commits, files, insertions, $"and **{deletions}** deletion{Plural(deletions)}");

var statistics = new List<(string Contributor, int Files, int Insertions, int Deletions)>();
foreach (var group in commitsGrouping)
{
if (topContributors.Count >= top3) break;
Expand All @@ -220,6 +220,7 @@ Task("CreateReleaseNotes")
}
else // multiple candidates with the same number of commits, so, group by files changed
{
var statistics = new List<(string Contributor, int Files, int Insertions, int Deletions)>();
var shortstatRegex = new Regex(@"^\s*(?'files'\d+)\s+files?\s+changed(?'ins',\s+(?'insertions'\d+)\s+insertions?\(\+\))?(?'del',\s+(?'deletions'\d+)\s+deletions?\(\-\))?\s*$");
// Collect statistics from git log & shortlog
foreach (var author in group.authors)
Expand Down Expand Up @@ -315,15 +316,15 @@ private void WriteReleaseNotes()
Information($"RUN {nameof(WriteReleaseNotes)} ...");

EnsureDirectoryExists(packagesDir);
System.IO.File.WriteAllLines(releaseNotesFile, releaseNotes);
System.IO.File.WriteAllLines(releaseNotesFile, releaseNotes, Encoding.UTF8);

var content = System.IO.File.ReadAllText(releaseNotesFile);
var content = System.IO.File.ReadAllText(releaseNotesFile, Encoding.UTF8);
if (string.IsNullOrEmpty(content))
{
System.IO.File.WriteAllText(releaseNotesFile, "No commits since last release");
}

Information($"Release notes are >>>\n{content}<<<");
Information("Release notes are >>>\n{0}<<<", content);
Information($"EXITED {nameof(WriteReleaseNotes)}");
}

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
project = 'Ocelot'
copyright = ' 2023 ThreeMammals Ocelot team'
author = 'Tom Pallister, Ocelot Core team at ThreeMammals'
release = '21.0'
release = '22.0'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion docs/features/caching.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Finally, in order to use caching on a route in your Route configuration add this

.. code-block:: json
"FileCacheOptions": { "TtlSeconds": 15, "Region": "somename" }
"FileCacheOptions": { "TtlSeconds": 15, "Region": "europe-central" }
In this example **TtlSeconds** is set to 15 which means the cache will expire after 15 seconds.
The **Region** represents a region of caching.
Expand Down
2 changes: 2 additions & 0 deletions docs/features/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ Use ``HttpHandlerOptions`` in a Route configuration to set up ``HttpHandler`` be

* **MaxConnectionsPerServer** This controls how many connections the internal ``HttpClient`` will open. This can be set at Route or global level.

.. _ssl-errors:

SSL Errors
----------

Expand Down
151 changes: 143 additions & 8 deletions docs/features/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,158 @@ Logging
=======

Ocelot uses the standard logging interfaces ``ILoggerFactory`` and ``ILogger<T>`` at the moment.
This is encapsulated in ``IOcelotLogger`` and ``IOcelotLoggerFactory`` with an implementation for the standard `ASP.NET Core logging <https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/>`_ stuff at the moment.
This is because Ocelot adds some extra info to the logs such as **request ID** if it is configured.
This is encapsulated in ``IOcelotLogger`` and ``IOcelotLoggerFactory`` with the implementation for the standard `ASP.NET Core logging <https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/>`_ stuff at the moment.
This is because Ocelot adds some extra info to the logs such as **RequestId** if it is configured.

There is a global `error handler middleware <https://github.com/search?q=repo%3AThreeMammals%2FOcelot%20ExceptionHandlerMiddleware&type=code>`_ that should catch any exceptions thrown and log them as errors.

Finally, if logging is set to **Trace** level, Ocelot will log starting, finishing and any middlewares that throw an exception which can be quite useful.
Finally, if logging is set to ``Trace`` level, Ocelot will log starting, finishing and any middlewares that throw an exception which can be quite useful.

Request ID
----------

The reason for not just using `bog standard <https://notoneoffbritishisms.com/2015/03/27/bog-standard/>`_ framework logging is that
we could not work out how to override the request id that get's logged when setting **IncludeScopes** to ``true`` for logging settings.
we could not work out how to override the **RequestId** that get's logged when setting **IncludeScopes** to ``true`` for logging settings.
Nicely onto the next feature.

Every log record has these 2 properties:

* **RequestId** represents ID of the current request as plain string, for example ``0HMVD33IIJRFR:00000001``
* **PreviousRequestId** represents ID of the previous request

As an ``IOcelotLogger`` interface object being injected to constructors of service classes, current default Ocelot logger (``OcelotLogger`` class) reads these 2 properties from the ``IRequestScopedDataRepository`` interface object.
Find out more about these properties and other details on the *Request ID* logging feature in the :doc:`../features/requestid` chapter.

.. _logging-warning:

Warning
-------

If you are logging to `Console <https://learn.microsoft.com/en-us/dotnet/api/system.console>`_, you will get terrible performance.
The team has had so many issues about performance issues with Ocelot and it is always logging level **Debug**, logging to `Console <https://learn.microsoft.com/en-us/dotnet/api/system.console>`_.
If you are logging to MS `Console <https://learn.microsoft.com/en-us/dotnet/api/system.console>`_, you will get terrible performance.
The team has had so many issues about performance issues with Ocelot and it is always logging level ``Debug``, logging to `Console <https://learn.microsoft.com/en-us/dotnet/api/system.console>`_.

* **Warning!** Make sure you are logging to something proper in production environment!
* Use **Error** and **Critical** levels in production environment!
* Use **Warning** level in testing environment!
* Use ``Error`` and ``Critical`` levels in production environment!
* Use ``Warning`` level in testing & staging environments!

These and other recommendations are below in the :ref:`logging-best-practices` section.

.. _logging-best-practices:

Best Practices
--------------

| Microsoft Learn сomplete reference: `Logging in .NET Core and ASP.NET Core <https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/>`_
Our recommendations to gain Ocelot best logging are the following.

First
^^^^^

Ensure minimum level while `Configure logging <https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/#configure-logging>`_.
The minimum log level is set in the application's ``appsettings.json`` file. This level is defined in the **Logging** section, for example:

.. code-block:: json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Whether using `Serilog <https://serilog.net/>`_ or the standard Microsoft providers, the logging configuration will be retrieved from this section.

.. code-block:: csharp
.ConfigureAppConfiguration((_, config) =>
{
config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", false, false);
// ...
})
However, there is one thing to be aware of. It is possible to use the ``SetMinimumLevel()`` method to define the minimum logging level.
Be careful and make sure you set the log level in one place only, like:

.. code-block:: csharp
ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(minLogLevel);
logging.AddConsole(); // MS Console for Development and/or Testing environments only
})
Please also use the ``ClearProviders()`` method, so that only the providers you wish to use are taken into account, as in the example above, the console.

Second
^^^^^^

Ensure proper usage of minimum logging level for each environment: development, testing, production, etc.
So, once again, read important notes of the :ref:`logging-warning` section!

Third
^^^^^

Ocelot's logging has been improved in `22.0 <https://github.com/ThreeMammals/Ocelot/releases/tag/22.0.0>`_ version:
it is now possible to use a factory method for message strings that will only be executed if the minimum log level allows it.

For example, let's take a message containing information about several variables that should only be generated if the minimum log level is ``Debug``.
If the minimum log level is ``Warning`` then the string is never generated.

Therefore, when the string contains dynamic information aka ``string.Format``, or string value is generated by `string interpolation <https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation>`_ expression,
it is recommended to call the log method using anonymous delegate via an ``=>`` expression function:

.. code-block:: csharp
Logger.LogDebug(() => $"downstream templates are {string.Join(", ", response.Data.Route.DownstreamRoute.Select(r => r.DownstreamPathTemplate.Value))}");
otherwise a constant string is sufficient

.. code-block:: csharp
Logger.LogDebug("My const string");
Performance Review
------------------

Ocelot's logging performance has been improved in version `22.0 <https://github.com/ThreeMammals/Ocelot/releases/tag/22.0.0>`__ (see PR `1745 <https://github.com/ThreeMammals/Ocelot/pull/1745>`_).
These changes were requested as part of issue `1744 <https://github.com/ThreeMammals/Ocelot/issues/1744>`_ after team's `discussion <https://github.com/ThreeMammals/Ocelot/discussions/1736>`_.

Top Logging Performance?
^^^^^^^^^^^^^^^^^^^^^^^^

Here is a quick recipe for your Production environment!
You need to ensure the minimal level is ``Critical`` or ``None``. Nothing more!
For sure, having top logging performance means having less log records written by logging provider. So, logs should be pretty empty.

Anyway, during the first time after a version release to production, we recommend to watch the system and current version app behavior by specifying ``Error`` minimum level.
If release engineer will ensure stability of the version in production then minimum level can be increased to ``Critical`` or ``None`` to gain top performance.
Technically this will switch off the logging feature at all.

Run Benchmarks
^^^^^^^^^^^^^^

We have 2 types of benchmarks currently

* ``SerilogBenchmarks`` with Serilog logging to a file. See ``ConfigureLogging`` method with ``logging.AddSerilog(_logger);``
* ``MsLoggerBenchmarks`` with MS default logging to MS Console. See ``ConfigureLogging`` method with ``logging.AddConsole();``

Benchmark results largely depend on the environment and hardware on which they run.
We are pleased to invite you to run Logging benchmarks on your machine by the following instructions below.

1. Open PowerShell or Command Prompt console
2. Build Ocelot solution in Release mode: ``dotnet build --configuration Release``
3. Go to ``test\Ocelot.Benchmarks\bin\Release\`` folder.
4. Choose .NET version changing the folder, for example to ``net8.0``
5. Run **Ocelot.Benchmarks.exe**: ``.\Ocelot.Benchmarks.exe``
6. Run ``SerilogBenchmarks`` or ``MsLoggerBenchmarks`` by pressing appropriate number of a benchmark: ``5`` or ``6``, + Enter
7. Wait for 3+ minutes to complete benchmark, and get final results.
8. Read and analize your benchmark session results.

Indicators
^^^^^^^^^^

``To be developed...``
Loading

0 comments on commit d24d5c9

Please sign in to comment.