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

refactor: Apply SLF4J best practices #10161

Merged

Conversation

timtebeek
Copy link
Contributor

Hi all, continuation here of earlier work on

I've run these three recipes together, to hopefully improve the logging output, with some small fixes thrown in too:

When looking at other projects these fixes could be applied a few more times:
image

Use this link to re-run the recipe: https://app.moderne.io/recipes/builder/NBXKac4Ye?organizationId=TWljcm9uYXV0

@timtebeek timtebeek marked this pull request as ready for review November 26, 2023 17:31
@sdelamo sdelamo added this to the 4.2.1 milestone Nov 30, 2023
@altro3
Copy link
Contributor

altro3 commented Dec 1, 2023

It is interesting that this change is not entirely correct: it makes sense to use placeholders only if you do not have a preliminary check for isDebugEnabled / isInfoEnabled / ... . In general, they were invented precisely for this purpose, to simplify the code, but at the same time not to carry out unnecessary calculations. That is, when you call a logger with some calculations, and then it turns out that logging is not happening due to another level of logging, but you have already spent time calculating the parameters.

In general, what I want to say is that the current changes will result in logging execution being slower than before, even if only slightly.

But since the slowdown is really insignificant, they can be done.

An example of such changes:
изображение

@timtebeek
Copy link
Contributor Author

It is interesting that this change is not entirely correct: it makes sense to use placeholders only if you do not have a preliminary check for isDebugEnabled / isInfoEnabled / ... . In general, they were invented precisely for this purpose, to simplify the code, but at the same time not to carry out unnecessary calculations. That is, when you call a logger with some calculations, and then it turns out that logging is not happening due to another level of logging, but you have already spent time calculating the parameters.

In general, what I want to say is that the current changes will result in logging execution being slower than before, even if only slightly.

Interesting perspective, thanks! So if I understand you correctly you're saying not to use parameterized logging when contained within a logging guard block? As then the arguments are guaranteed to be used if executed, and String concatenation is faster than the log string formatting.

Scrolling through the pull request changes again it seems the project is pretty consistent in using guard blocks. An alternative point can also be made that those guard blocks are perhaps not as needed when using parameterized logging, and could clean up the code a bit. Not saying we should do this, but it's an interesting thought.

Looking at for instance the following snippet, in the before situation the guard block prevented unnecessary string concatenation, whereas when using parameterized logging the if could also be removed, such that you only interact with LOG once. I have no measurements on performance there, but the code reads cleaner without the guarding conditional.

         if (LOG.isDebugEnabled()) {
-            LOG.debug("Swallowed an IOException caused by client connectivity: " + cause.getMessage(), cause);
+            LOG.debug("Swallowed an IOException caused by client connectivity: {}", cause.getMessage(), cause);
         }

Curious to hear your thoughts; I'd now be inclined to write a recipe to clear out unnecessary guard blocks, even if it's not applied here. :)

@altro3
Copy link
Contributor

altro3 commented Dec 1, 2023

Yes, that's right, your example is correct. Of course, string concatenation is faster than string parsing and replacing placeholders.

Yes, if you switched to placeholders, then there is no need to check the logging level before doing so. The check will still occur in the Slf4J implementation. for example, in the ch.qos.logback.classic.Logger class. But even here everything is not entirely clear: in the logger, the level is checked not immediately, but after several quick operations.

Therefore, the following conclusions can be drawn:

  1. The most effective method of logging in terms of speed (But at the same time, the most inconvenient method, which existed BEFORE the creation of Slf4J and was proposed in Log4J):
if (LOG.isDebugEnabled()) {
    LOG.debug("Swallowed an IOException caused by client connectivity: " + cause.getMessage(), cause);
}
  1. The most convenient way, but with several additional internal operations:
LOG.debug("Swallowed an IOException caused by client connectivity: {}", cause.getMessage(), cause);

As always, we have a standard conflict in programming: convenience or performance :-)

@timtebeek
Copy link
Contributor Author

Agreed! And then this PR somewhat counter-intuitively uses both guards and parameterized logging, with the performance penalty you've indicated. So then I'll leave up to all of you if you still want to merge this for the readability improvements and minor fixes, or revisit at a later point in time.

As perhaps known these code changes were mostly automated (apart from the fixes and reverts), so no harm in rejecting a PR if you're not happy with it. Merely trying to help, and learn & improve in the process. :)

@altro3
Copy link
Contributor

altro3 commented Dec 1, 2023

The guys will decide that :). There is nothing wrong with these changes. There is little performance loss. I would just then remove the checks at the logging level, because... they will happen inside the method anyway. Those. in the case of logging, it seems to me that it is quite possible to sacrifice performance for the sake of convenience. But it's not up to me to decide ;-)

In any case, I think it’s worth adding to these changes and removing checks at the logging level in cases where there are no calculations

@sdelamo
Copy link
Contributor

sdelamo commented Dec 1, 2023

what do you think? @dstepanov I was about to merge this.

@sdelamo sdelamo merged commit 08bb910 into micronaut-projects:4.2.x Dec 1, 2023
10 checks passed
@timtebeek timtebeek deleted the refactor/slf-4-j-best-practices branch December 1, 2023 10:17
sdelamo pushed a commit that referenced this pull request Dec 3, 2023
yawkat pushed a commit that referenced this pull request Dec 4, 2023
* Remove unused Netty attributes

* Fix

* Fix methods not respecting the array type when comparing (#10168)

* ContextualConnection intercepted missing method repro

* Change test package

* Update ConnectionInterceptorSpec.groovy

* Updated example not to use Connection

* Fix methods not respecting the array type when comparing

---------

Co-authored-by: radovanradic <[email protected]>

* fix(deps): update dependency org.neo4j.driver:neo4j-java-driver to v1.7.6 (#10152)

* fix(deps): update dependency org.neo4j.driver:neo4j-java-driver to v1.7.6

* neo4j-java-driver to 5.14.0 (matching version used in micronaut-neo4j)

* fix inject-groovy tests for update to neo4j-java-driver with breaking changes

* fix inject-java tests for update to neo4j-java-driver with breaking changes

* Fix inject-kotlin tests for update to neo4j-java-driver with breaking changes. Includes re-enabling most of ConfigurationPropertiesBuilderSpec that was entirely commented out on #8837.

* neo4j-java-driver to 5.15.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Dean Wette <[email protected]>

* chore(deps): update gradle/gradle-build-action action to v2.10.0 (#10170)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update kotlin monorepo to v1.9.21 (#10157)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency gradle to v8.5 (#10174)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update common files (#10183)

* fix(deps): update groovy monorepo to v4.0.16 (#10182)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update dependency ch.qos.logback:logback-classic to v1.4.13 (#10166)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* refactor: Apply SLF4J best practices (#10161)

* Replaces usages of BeanContext::run with ApplicationContext::run (#10184)

* Micronaut Validation 4.2.0

* Micronaut SQL 5.3.0

* rxjava 2.1.0

* :%s/BeanContext::run/ApplicationContext::run tests

* :%s/BeanContext::run/DefaultBeanContext::start tests

* fix(deps): update managed.ksp to v1.9.21-1.0.15 (#10169)

* fix(deps): update managed.ksp to v1.9.21-1.0.15

* This requires more memory for Kotest 🤔

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Sergio del Amo <[email protected]>
Co-authored-by: Tim Yates <[email protected]>

* [skip ci] Release v4.2.1

* Back to 4.2.2-SNAPSHOT

* checkstyle: [EmptyLineSeparator]

---------

Co-authored-by: radovanradic <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Dean Wette <[email protected]>
Co-authored-by: micronaut-build <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
Co-authored-by: Sergio del Amo <[email protected]>
Co-authored-by: Tim Yates <[email protected]>
Co-authored-by: micronaut-build <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants