├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── comment-pr.yml │ ├── publish.yml │ ├── receive-pr.yml │ ├── repository-backup.yml │ └── stale.yml ├── .gitignore ├── LICENSE.md ├── LICENSE ├── apache-license-v2.txt └── moderne-source-available-license.md ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle ├── licenseHeader.txt └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lombok.config ├── settings.gradle.kts ├── src ├── main │ ├── java │ │ └── org │ │ │ └── openrewrite │ │ │ └── java │ │ │ └── logging │ │ │ ├── AddLogger.java │ │ │ ├── CatchBlockLogLevel.java │ │ │ ├── ChangeLoggersToPrivate.java │ │ │ ├── ChangeLombokLogAnnotation.java │ │ │ ├── LoggingFramework.java │ │ │ ├── ParameterizedLogging.java │ │ │ ├── PrintStackTraceToLogError.java │ │ │ ├── SystemErrToLogging.java │ │ │ ├── SystemOutToLogging.java │ │ │ ├── SystemPrintToLogging.java │ │ │ ├── jul │ │ │ └── LoggerLevelArgumentToMethod.java │ │ │ ├── log4j │ │ │ ├── ConvertJulEntering.java │ │ │ ├── ConvertJulExiting.java │ │ │ ├── LoggerSetLevelToConfigurator.java │ │ │ ├── LoggingExceptionConcatenation.java │ │ │ ├── PrependRandomName.java │ │ │ └── package-info.java │ │ │ ├── logback │ │ │ ├── ConfigureLoggerLevel.java │ │ │ ├── Log4jAppenderToLogback.java │ │ │ ├── Log4jLayoutToLogback.java │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ └── slf4j │ │ │ ├── ChangeLogLevel.java │ │ │ ├── CompleteExceptionLogging.java │ │ │ ├── JulGetLoggerToLoggerFactory.java │ │ │ ├── JulIsLoggableToIsEnabled.java │ │ │ ├── JulLevelAllToTrace.java │ │ │ ├── JulParameterizedArguments.java │ │ │ ├── JulToSlf4jLambdaSupplier.java │ │ │ ├── JulToSlf4jLambdaSupplierWithThrowable.java │ │ │ ├── JulToSlf4jSimpleCallsWithThrowable.java │ │ │ ├── LoggersNamedForEnclosingClass.java │ │ │ ├── Slf4jLogShouldBeConstant.java │ │ │ ├── WrapExpensiveLogStatementsInConditionals.java │ │ │ └── package-info.java │ └── resources │ │ └── META-INF │ │ └── rewrite │ │ ├── category.yml │ │ ├── classpath.tsv.zip │ │ ├── examples.yml │ │ ├── log4j.yml │ │ ├── logback.yml │ │ └── slf4j.yml └── test │ └── java │ └── org │ └── openrewrite │ └── java │ └── logging │ ├── AddLoggerTest.java │ ├── CatchBlockLogLevelTest.java │ ├── ChangeLoggersToPrivateTest.java │ ├── ParameterizedLoggingTest.java │ ├── PrintStackTraceToLogErrorTest.java │ ├── SystemErrToLoggingTest.java │ ├── SystemOutToLoggingTest.java │ ├── jul │ └── LoggerLevelArgumentToMethodTest.java │ ├── log4j │ ├── CommonsLoggingToLog4jTest.java │ ├── ConvertJulEnteringTest.java │ ├── ConvertJulExitingTest.java │ ├── JulToLog4jTest.java │ ├── Log4j1ToLog4j2Test.java │ ├── LoggingExceptionConcatenationTest.java │ ├── PrependRandomNameTest.java │ └── Slf4jToLog4jTest.java │ ├── logback │ ├── ConfigureLoggerLevelTest.java │ ├── Log4jAppenderToLogbackTest.java │ └── Log4jLayoutToLogbackTest.java │ └── slf4j │ ├── ChangeLogLevelTest.java │ ├── CommonsLoggingToSlf4j1Test.java │ ├── CompleteExceptionLoggingTest.java │ ├── JulParameterizedArgumentsTest.java │ ├── JulToSlf4jTest.java │ ├── Log4j1ToSlf4j1Test.java │ ├── Log4j2ToSlf4j1Test.java │ ├── LoggersNamedForEnclosingClassTest.java │ ├── Slf4jBestPracticesTest.java │ ├── Slf4jLogShouldBeConstantTest.java │ └── WrapExpensiveLogStatementsInConditionalsTest.java └── suppressions.xml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | 7 | [src/test*/java/**.java] 8 | indent_size = 4 9 | ij_continuation_indent_size = 2 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: / 6 | schedule: 7 | interval: daily 8 | commit-message: 9 | prefix: "chore(ci)" 10 | - package-ecosystem: gradle 11 | directory: / 12 | schedule: 13 | interval: daily 14 | commit-message: 15 | prefix: "chore(ci)" 16 | open-pull-requests-limit: 0 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ci 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | tags-ignore: 9 | - "*" 10 | pull_request: 11 | branches: 12 | - main 13 | workflow_dispatch: {} 14 | schedule: 15 | - cron: 0 18 * * * 16 | 17 | concurrency: 18 | group: ci-${{ github.ref }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | build: 23 | uses: openrewrite/gh-automation/.github/workflows/ci-gradle.yml@main 24 | secrets: 25 | gradle_enterprise_access_key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} 26 | ossrh_username: ${{ secrets.OSSRH_USERNAME }} 27 | ossrh_token: ${{ secrets.OSSRH_TOKEN }} 28 | ossrh_signing_key: ${{ secrets.OSSRH_SIGNING_KEY }} 29 | ossrh_signing_password: ${{ secrets.OSSRH_SIGNING_PASSWORD }} 30 | OPS_GITHUB_ACTIONS_WEBHOOK: ${{ secrets.OPS_GITHUB_ACTIONS_WEBHOOK }} 31 | -------------------------------------------------------------------------------- /.github/workflows/comment-pr.yml: -------------------------------------------------------------------------------- 1 | name: comment-pr 2 | 3 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow 4 | on: 5 | workflow_run: 6 | workflows: ["receive-pr"] 7 | types: 8 | - completed 9 | 10 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ 11 | # Since this pull request has write permissions on the target repo, we should **NOT** execute any untrusted code. 12 | jobs: 13 | post-suggestions: 14 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 15 | uses: openrewrite/gh-automation/.github/workflows/comment-pr.yml@main 16 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: publish 3 | 4 | on: 5 | push: 6 | tags: 7 | - v[0-9]+.[0-9]+.[0-9]+ 8 | - v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+ 9 | 10 | concurrency: 11 | group: publish-${{ github.ref }} 12 | cancel-in-progress: false 13 | 14 | jobs: 15 | release: 16 | uses: openrewrite/gh-automation/.github/workflows/publish-gradle.yml@main 17 | secrets: 18 | gradle_enterprise_access_key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} 19 | ossrh_username: ${{ secrets.OSSRH_USERNAME }} 20 | ossrh_token: ${{ secrets.OSSRH_TOKEN }} 21 | ossrh_signing_key: ${{ secrets.OSSRH_SIGNING_KEY }} 22 | ossrh_signing_password: ${{ secrets.OSSRH_SIGNING_PASSWORD }} 23 | -------------------------------------------------------------------------------- /.github/workflows/receive-pr.yml: -------------------------------------------------------------------------------- 1 | name: receive-pr 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize] 6 | branches: 7 | - main 8 | 9 | concurrency: 10 | group: '${{ github.workflow }} @ ${{ github.ref }}' 11 | cancel-in-progress: true 12 | 13 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ 14 | # Since this pull request receives untrusted code, we should **NOT** have any secrets in the environment. 15 | jobs: 16 | upload-patch: 17 | uses: openrewrite/gh-automation/.github/workflows/receive-pr.yml@main -------------------------------------------------------------------------------- /.github/workflows/repository-backup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: repository-backup 3 | on: 4 | workflow_dispatch: {} 5 | schedule: 6 | - cron: 0 17 * * * 7 | 8 | concurrency: 9 | group: backup-${{ github.ref }} 10 | cancel-in-progress: false 11 | 12 | jobs: 13 | repository-backup: 14 | uses: openrewrite/gh-automation/.github/workflows/repository-backup.yml@main 15 | secrets: 16 | bucket_mirror_target: ${{ secrets.S3_GITHUB_REPOSITORY_BACKUPS_BUCKET_NAME }} 17 | bucket_access_key_id: ${{ secrets.S3_GITHUB_REPOSITORY_BACKUPS_ACCESS_KEY_ID }} 18 | bucket_secret_access_key: ${{ secrets.S3_GITHUB_REPOSITORY_BACKUPS_SECRET_ACCESS_KEY }} 19 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: stale 3 | 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 36 4 * * 1 8 | 9 | jobs: 10 | build: 11 | uses: openrewrite/gh-automation/.github/workflows/stale.yml@main 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .gradle/ 3 | out/ 4 | .idea/ 5 | src/main/generated/ 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | LICENSE/moderne-source-available-license.md -------------------------------------------------------------------------------- /LICENSE/moderne-source-available-license.md: -------------------------------------------------------------------------------- 1 | # Moderne Source Available License 2 | 3 | ## Acceptance 4 | 5 | This Agreement sets forth the terms and conditions on which the Licensor makes available the Software. By installing, downloading, copying, accessing, using, creating derivative works of, or distributing any of the Software, You agree to all of the terms and conditions of this Agreement. 6 | If You are receiving the Software on behalf of an entity, sole proprietorship or other organization, You represent and warrant that You have the authority to agree to this Agreement on behalf of such organization. 7 | 8 | The Licensor reserves the right to update this Agreement from time to time. 9 | 10 | The terms below have the meanings set forth below for purposes of this Agreement: 11 | 12 | ## Definitions 13 | 14 | Agreement: this Moderne Source Available License Agreement. 15 | 16 | Control: ownership, directly or indirectly, of substantially all the assets of an entity, or the power to direct its management or policies by vote, contract, or otherwise. 17 | 18 | License: a license as described in the License or Patent paragraph below. 19 | 20 | Licensor: Moderne, Inc. on behalf of itself and its subsidiaries worldwide. 21 | 22 | Modify, Modified, or Modification: copy from or adapt all or part of the work in a fashion requiring copyright permission (including, without limitation, creating a derivative work via linking or otherwise) other than making an exact unlinked copy. The resulting work is called a Modified version of the earlier work or a Modification. 23 | 24 | Software: The Licensor's software components provided to You by the Licensor under this Agreement. 25 | 26 | Trademark: the trademarks, service marks, and any other similar rights. 27 | 28 | You: the recipient of the Software pursuant to this Agreement, including both (a) the individual agreeing to this Agreement and (b) if receiving the Software or agreeing on behalf of or representing an entity, sole proprietorship or other organization, that organization. 29 | 30 | Your Company: any legal entity, sole proprietorship, or other kind of organization that You work for or represent, plus all organizations that have Control over, are under the Control of, or are under common Control with that organization. 31 | 32 | Your Licenses: means all the Licenses granted to You under this Agreement. 33 | 34 | 35 | ## License 36 | 37 | The Licensor grants You a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license under the Licensor's copyrights to use, copy, distribute internally, and prepare derivative works of the Software, in each case subject to, and conditional on compliance with, the limitations and conditions below. 38 | 39 | ## Limitations 40 | 41 | You may not and will not make the functionality of the Software or a Modified version available to third parties as a service or distribute the Software or a Modified version in a manner that makes the functionality of the Software directly or indirectly available to third parties. 42 | 43 | Making the functionality of the Software or Modified version available to third parties includes, without limitation, enabling third parties to interact with the functionality of the Software or Modified version in distributed form or remotely through a computer network, offering a product or service, the value of which derives to any extent from the value of the Software or Modified version, or offering a product or service that accomplishes for users any purpose of the Software or Modified version. 44 | 45 | Examples of third parties that are prohibited under this limitation include but are not limited to: 46 | * Sourcegraph and Sourcegraph Batch Changes 47 | * Amazon Q Code Transformer 48 | * Broadcom Application Advisor 49 | 50 | You may not and will not alter, remove, or obscure any licensing, copyright, or other notices of the Licensor in the Software. Any use of the Licensor's Trademarks is subject to applicable law (but no license is granted hereunder with respect to the Licensor's Trademarks). 51 | 52 | ## Patents 53 | 54 | The Licensor grants You a license, under any of the Licensor's patent claims covering the Software, to make, have made, use, import and have imported the Software, in each case subject to, and conditional upon compliance with, the limitations and conditions in this Agreement. This license does not cover any patent claims that You cause to be infringed by Modifications or additions to the Software. If You or Your Company make any claim that the Software (or any Modification owned by or available from the Licensor) infringes or contributes to infringement of any patent, the patent license granted under this Agreement ends immediately. 55 | 56 | ## Notices 57 | 58 | You must ensure that anyone who gets a copy of any part of the Software or a Modification from You also gets a copy of the terms and conditions in this Agreement. 59 | 60 | If You modify the Software, You must include in any Modified copies of the Software prominent notices stating that You have Modified the Software. 61 | 62 | ## No Other Rights 63 | 64 | The terms and conditions of this Agreement do not imply any licenses other than those expressly granted in this Agreement. 65 | 66 | ## Termination 67 | 68 | If You violate this Agreement or if You engage in any activity regarding the Software beyond or in conflict with the terms of this Agreement, such activity is not licensed, and Your Licenses will automatically terminate. If the Licensor provides You with a notice of your violation and gives you an option to cure, and You cease and cure all violations of this License no later than 30 days after You receive that notice, Your Licenses will be reinstated retroactively. However, if You violate this Agreement after such reinstatement, any additional violation of this Agreement will cause your Licenses to terminate automatically and permanently. 69 | 70 | ## No Liability 71 | 72 | **_AS FAR AS THE LAW ALLOWS, THE SOFTWARE COMES :undefined:AS IS,:undefined: WITHOUT ANY WARRANTY, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY WHATSOEVER, INCLUDING WITHOUT LIMITATION ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR ANY PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. FURTHERMORE THE LICENSOR WILL NOT BE LIABLE TO YOU FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES (OR, TO THE EXTENT LEGALLY PERMISSIBLE, ANY OTHER DAMAGES) ARISING OUT OF THIS AGREEMENT OR IN CONNECTION WITH THE SOFTWARE, UNDER ANY KIND OF LEGAL CLAIM (INCLUDING, WITHOUT LIMITATION, CONTRACT, TORT OR NEGLIGENCE)._** 73 | 74 | ## Governing Law and Jurisdiction 75 | 76 | This Agreement will be construed and enforced in all respects in accordance with the laws of the State of Delaware, U.S.A., without reference to its choice of law rules. The courts located in Delaware have exclusive jurisdiction for all purposes relating to this Agreement, provided that the Licensor may apply to any court of competent jurisdiction for injunctive relief. 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
7 |
3 | Licensed under the Moderne Source Available License (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 |
7 | https://docs.moderne.io/licensing/moderne-source-available-license 8 |
9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openrewrite/rewrite-logging-frameworks/1e14228375c9b918d5f82da7737d574b8eb111d7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionSha256Sum=7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | # https://projectlombok.org/features/configuration 2 | config.stopBubbling = true 3 | lombok.addNullAnnotations = CUSTOM:org.openrewrite.internal.lang.NonNull:org.openrewrite.internal.lang.Nullable 4 | lombok.copyableAnnotations += org.openrewrite.internal.lang.Nullable 5 | lombok.copyableAnnotations += org.openrewrite.internal.lang.NonNull 6 | lombok.anyConstructor.addConstructorProperties=true 7 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | rootProject.name = "rewrite-logging-frameworks" 9 | 10 | plugins { 11 | id("com.gradle.develocity") version "latest.release" 12 | id("com.gradle.common-custom-user-data-gradle-plugin") version "latest.release" 13 | } 14 | 15 | develocity { 16 | server = "https://ge.openrewrite.org/" 17 | 18 | val isCiServer = System.getenv("CI")?.equals("true") ?: false 19 | val accessKey = System.getenv("GRADLE_ENTERPRISE_ACCESS_KEY") 20 | val authenticated = !accessKey.isNullOrBlank() 21 | buildCache { 22 | remote(develocity.buildCache) { 23 | isEnabled = true 24 | isPush = isCiServer && authenticated 25 | } 26 | } 27 | 28 | buildScan { 29 | capture { 30 | fileFingerprints = true 31 | } 32 | publishing { 33 | onlyIf { 34 | authenticated 35 | } 36 | } 37 | uploadInBackground = !isCiServer 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/openrewrite/java/logging/AddLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 the original author or authors. 3 | *
4 | * Licensed under the Moderne Source Available License (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license 9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import org.openrewrite.ExecutionContext;
19 | import org.openrewrite.TreeVisitor;
20 | import org.openrewrite.internal.ListUtils;
21 | import org.openrewrite.java.JavaIsoVisitor;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.java.JavaTemplate;
24 | import org.openrewrite.java.JavaVisitor;
25 | import org.openrewrite.java.format.AutoFormatVisitor;
26 | import org.openrewrite.java.search.FindFieldsOfType;
27 | import org.openrewrite.java.search.FindInheritedFields;
28 | import org.openrewrite.java.tree.J;
29 | import org.openrewrite.java.tree.Statement;
30 |
31 | import java.util.Comparator;
32 | import java.util.function.Function;
33 |
34 | import static java.util.Objects.requireNonNull;
35 |
36 | /**
37 | * @author Edward Harman
38 | */
39 | public class AddLogger extends JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.openrewrite.*;
21 | import org.openrewrite.java.JavaIsoVisitor;
22 | import org.openrewrite.java.MethodMatcher;
23 | import org.openrewrite.java.search.UsesMethod;
24 | import org.openrewrite.java.tree.J;
25 | import org.openrewrite.java.tree.JavaType;
26 | import org.openrewrite.java.tree.TypeUtils;
27 |
28 | import java.util.concurrent.atomic.AtomicBoolean;
29 |
30 | @Value
31 | @EqualsAndHashCode(callSuper = false)
32 | public class CatchBlockLogLevel extends Recipe {
33 |
34 | @Override
35 | public String getDisplayName() {
36 | return "Catch block log level";
37 | }
38 |
39 | @Override
40 | public String getDescription() {
41 | return "Sometimes exceptions are caught and logged at the wrong log level. This will set the log level of " +
42 | "logging statements within a catch block not containing an exception to \"warn\", and the log level of " +
43 | "logging statements containing an exception to \"error\". " +
44 | "This supports SLF4J, Log4J1, Log4j2, and Logback.";
45 | }
46 |
47 | private static final MethodMatcher SLF4J_MATCHER = new MethodMatcher("org.slf4j.Logger *(..)");
48 | private static final MethodMatcher LOG4J1_MATCHER = new MethodMatcher("org.apache.log4j.Category *(..)");
49 | private static final MethodMatcher LOG4J2_MATCHER = new MethodMatcher("org.apache.logging.log4j.Logger *(..)");
50 | private static final MethodMatcher LOGBACK_MATCHER = new MethodMatcher("ch.qos.logback.classic.Logger *(..)");
51 |
52 | @Override
53 | public TreeVisitor, ExecutionContext> getVisitor() {
54 | TreeVisitor, ExecutionContext> check = Preconditions.or(
55 | new UsesMethod<>(SLF4J_MATCHER),
56 | new UsesMethod<>(LOG4J1_MATCHER),
57 | new UsesMethod<>(LOG4J2_MATCHER),
58 | new UsesMethod<>(LOGBACK_MATCHER));
59 |
60 | return Preconditions.check(check, new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.jspecify.annotations.Nullable;
21 | import org.openrewrite.*;
22 | import org.openrewrite.internal.ListUtils;
23 | import org.openrewrite.java.JavaIsoVisitor;
24 | import org.openrewrite.java.search.UsesType;
25 | import org.openrewrite.java.tree.J;
26 | import org.openrewrite.java.tree.JavaType;
27 | import org.openrewrite.java.tree.Space;
28 | import org.openrewrite.java.tree.TypeUtils;
29 | import org.openrewrite.marker.Markers;
30 |
31 | import java.util.Arrays;
32 | import java.util.List;
33 | import java.util.Set;
34 |
35 | import static java.util.Collections.emptyList;
36 | import static java.util.stream.Collectors.toSet;
37 |
38 | @Value
39 | @EqualsAndHashCode(callSuper = false)
40 | public class ChangeLoggersToPrivate extends Recipe {
41 |
42 | private static final Set
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import lombok.AllArgsConstructor;
19 | import org.jspecify.annotations.Nullable;
20 | import org.openrewrite.Option;
21 | import org.openrewrite.Recipe;
22 | import org.openrewrite.java.ChangeType;
23 |
24 | import java.util.List;
25 | import java.util.stream.Collectors;
26 | import java.util.stream.Stream;
27 |
28 | @AllArgsConstructor
29 | public class ChangeLombokLogAnnotation extends Recipe {
30 |
31 | @Override
32 | public String getDisplayName() {
33 | return "Replace any Lombok log annotations with target logging framework annotation";
34 | }
35 |
36 | @Override
37 | public String getDescription() {
38 | return "Replace Lombok annotations such as `@CommonsLog` and `@Log4j` with the target logging framework annotation, or `@Sl4fj` if not provided.";
39 | }
40 |
41 | @Option(displayName = "Logging framework",
42 | description = "The logging framework to use.",
43 | valid = {"SLF4J", "Log4J1", "Log4J2", "JUL", "COMMONS"},
44 | required = false)
45 | @Nullable
46 | private String loggingFramework;
47 |
48 | @Override
49 | public List
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import org.jspecify.annotations.Nullable;
19 | import org.openrewrite.ExecutionContext;
20 | import org.openrewrite.java.JavaParser;
21 | import org.openrewrite.java.JavaTemplate;
22 |
23 | public enum LoggingFramework {
24 | SLF4J("org.slf4j.Logger"),
25 | Log4J1("org.apache.log4j.Logger"),
26 | Log4J2("org.apache.logging.log4j.Logger"),
27 | JUL("java.util.logging.Logger"),
28 | COMMONS("org.apache.commons.logging.Log");
29 |
30 | private final String loggerType;
31 |
32 | LoggingFramework(String loggerType) {
33 | this.loggerType = loggerType;
34 | }
35 |
36 | public String getLoggerType() {
37 | return loggerType;
38 | }
39 |
40 | public static LoggingFramework fromOption(@Nullable String option) {
41 | if (option != null) {
42 | for (LoggingFramework value : values()) {
43 | if (value.toString().equalsIgnoreCase(option)) {
44 | return value;
45 | }
46 | }
47 | }
48 | return SLF4J;
49 | }
50 |
51 | public JavaTemplate getErrorTemplate(String message, ExecutionContext ctx) {
52 | switch (this) {
53 | case SLF4J:
54 | return JavaTemplate
55 | .builder("#{any(org.slf4j.Logger)}.error(" + message + ", #{any(java.lang.Throwable)})")
56 | .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "slf4j-api-2.1.+"))
57 | .build();
58 | case Log4J1:
59 | return JavaTemplate
60 | .builder("#{any(org.apache.log4j.Category)}.error(" + message + ", #{any(java.lang.Throwable)})")
61 | .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "log4j-1.2.+"))
62 | .build();
63 |
64 | case Log4J2:
65 | return JavaTemplate
66 | .builder("#{any(org.apache.logging.log4j.Logger)}.error(" + message + ", #{any(java.lang.Throwable)})")
67 | .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "log4j-api-2.+"))
68 | .build();
69 | case COMMONS:
70 | return JavaTemplate
71 | .builder("#{any(org.apache.commons.logging.Log)}.error(" + message + ", #{any(java.lang.Throwable)})")
72 | .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "commons-logging-1.3.+"))
73 | .build();
74 | case JUL:
75 | default:
76 | return JavaTemplate
77 | .builder("#{any(java.util.logging.Logger)}.log(Level.SEVERE, " + message + ", #{any(java.lang.Throwable)})")
78 | .imports("java.util.logging.Level")
79 | .build();
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/PrintStackTraceToLogError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.jspecify.annotations.Nullable;
21 | import org.openrewrite.*;
22 | import org.openrewrite.java.AnnotationMatcher;
23 | import org.openrewrite.java.JavaIsoVisitor;
24 | import org.openrewrite.java.MethodMatcher;
25 | import org.openrewrite.java.search.FindFieldsOfType;
26 | import org.openrewrite.java.search.UsesType;
27 | import org.openrewrite.java.service.AnnotationService;
28 | import org.openrewrite.java.tree.J;
29 | import org.openrewrite.java.tree.Space;
30 | import org.openrewrite.marker.Markers;
31 |
32 | import java.util.Collections;
33 | import java.util.Set;
34 |
35 | @Value
36 | @EqualsAndHashCode(callSuper = false)
37 | public class PrintStackTraceToLogError extends Recipe {
38 | @Option(displayName = "Add logger",
39 | description = "Add a logger field to the class if it isn't already present.",
40 | required = false)
41 | @Nullable
42 | Boolean addLogger;
43 |
44 | @Option(displayName = "Logger name",
45 | description = "The name of the logger to use when generating a field.",
46 | required = false,
47 | example = "log")
48 | @Nullable
49 | String loggerName;
50 |
51 | @Option(displayName = "Logging framework",
52 | description = "The logging framework to use.",
53 | valid = {"SLF4J", "Log4J1", "Log4J2", "JUL", "COMMONS"},
54 | required = false)
55 | @Nullable
56 | String loggingFramework;
57 |
58 | @Override
59 | public String getDisplayName() {
60 | return "Use logger instead of `printStackTrace()`";
61 | }
62 |
63 | @Override
64 | public String getDescription() {
65 | return "When a logger is present, log exceptions rather than calling `printStackTrace()`.";
66 | }
67 |
68 | @Override
69 | public TreeVisitor, ExecutionContext> getVisitor() {
70 | MethodMatcher printStackTrace = new MethodMatcher("java.lang.Throwable printStackTrace(..)");
71 | LoggingFramework framework = LoggingFramework.fromOption(loggingFramework);
72 | AnnotationMatcher lombokLogAnnotationMatcher = new AnnotationMatcher("@lombok.extern..*");
73 |
74 | JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Getter;
20 | import lombok.Value;
21 | import org.jspecify.annotations.Nullable;
22 | import org.openrewrite.Option;
23 | import org.openrewrite.Recipe;
24 |
25 | import java.util.Arrays;
26 | import java.util.List;
27 |
28 | @Value
29 | @EqualsAndHashCode(callSuper = false)
30 | public class SystemPrintToLogging extends Recipe {
31 | @Option(displayName = "Add logger",
32 | description = "Add a logger field to the class if it isn't already present.",
33 | required = false)
34 | @Nullable
35 | Boolean addLogger;
36 |
37 | @Option(displayName = "Logger name",
38 | description = "The name of the logger to use when generating a field.",
39 | required = false,
40 | example = "log")
41 | @Nullable
42 | String loggerName;
43 |
44 | @Option(displayName = "Logging framework",
45 | description = "The logging framework to use.",
46 | valid = {"SLF4J", "Log4J1", "Log4J2", "JUL", "COMMONS"},
47 | required = false)
48 | @Nullable
49 | String loggingFramework;
50 |
51 | @Option(displayName = "Level",
52 | description = "The logging level to turn `System.out` print statements into.",
53 | valid = {"trace", "debug", "info"},
54 | required = false)
55 | @Nullable
56 | String level;
57 |
58 | @Getter(lazy = true)
59 | List
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.openrewrite.ExecutionContext;
21 | import org.openrewrite.Preconditions;
22 | import org.openrewrite.Recipe;
23 | import org.openrewrite.TreeVisitor;
24 | import org.openrewrite.java.JavaIsoVisitor;
25 | import org.openrewrite.java.MethodMatcher;
26 | import org.openrewrite.java.search.UsesMethod;
27 | import org.openrewrite.java.tree.Expression;
28 | import org.openrewrite.java.tree.J;
29 | import org.openrewrite.java.tree.JavaType;
30 | import org.openrewrite.java.tree.Space;
31 | import org.openrewrite.marker.Markers;
32 |
33 | import java.util.ArrayList;
34 | import java.util.List;
35 |
36 | import static org.openrewrite.Tree.randomId;
37 |
38 | /**
39 | * This recipe rewrites JUL's {@link java.util.logging.Logger#entering} method.
40 | */
41 | @Value
42 | @EqualsAndHashCode(callSuper = false)
43 | public class ConvertJulEntering extends Recipe {
44 |
45 | private static final MethodMatcher METHOD_MATCHER = new MethodMatcher("java.util.logging.Logger entering(String, String, ..)", false);
46 |
47 | @Override
48 | public String getDisplayName() {
49 | return "Rewrites JUL's Logger#entering method to Log4j API";
50 | }
51 |
52 | @Override
53 | public String getDescription() {
54 | return "Replaces JUL's Logger#entering method calls to Log4j API Logger#traceEntry calls.";
55 | }
56 |
57 | @Override
58 | public TreeVisitor, ExecutionContext> getVisitor() {
59 | return Preconditions.check(new UsesMethod<>(METHOD_MATCHER), new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.openrewrite.ExecutionContext;
21 | import org.openrewrite.Preconditions;
22 | import org.openrewrite.Recipe;
23 | import org.openrewrite.TreeVisitor;
24 | import org.openrewrite.java.JavaIsoVisitor;
25 | import org.openrewrite.java.MethodMatcher;
26 | import org.openrewrite.java.search.UsesMethod;
27 | import org.openrewrite.java.tree.*;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | /**
33 | * This recipe rewrites JUL's {@link java.util.logging.Logger#entering} method.
34 | */
35 | @Value
36 | @EqualsAndHashCode(callSuper = false)
37 | public class ConvertJulExiting extends Recipe {
38 |
39 | private static final MethodMatcher METHOD_MATCHER = new MethodMatcher("java.util.logging.Logger exiting(String, String, ..)", false);
40 |
41 | @Override
42 | public String getDisplayName() {
43 | return "Rewrites JUL's Logger#exiting method to Log4j API";
44 | }
45 |
46 | @Override
47 | public String getDescription() {
48 | return "Replaces JUL's Logger#exiting method calls to Log4j API Logger#traceEntry calls.";
49 | }
50 |
51 | @Override
52 | public TreeVisitor, ExecutionContext> getVisitor() {
53 | return Preconditions.check(new UsesMethod<>(METHOD_MATCHER), new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.apache.logging.log4j.core.config.Configurator;
21 | import org.openrewrite.java.template.RecipeDescriptor;
22 |
23 | @RecipeDescriptor(
24 | name = "Convert Log4j `Logger.setLevel` to Log4j2 `Configurator.setLevel`",
25 | description = "Converts `org.apache.log4j.Logger.setLevel` to `org.apache.logging.log4j.core.config.Configurator.setLevel`.")
26 | public class LoggerSetLevelToConfigurator {
27 |
28 | @BeforeTemplate
29 | void before(org.apache.log4j.Logger logger, org.apache.log4j.Level level) {
30 | logger.setLevel(level);
31 | }
32 |
33 | @AfterTemplate
34 | void after(org.apache.logging.log4j.Logger logger, org.apache.logging.log4j.Level level) {
35 | Configurator.setLevel(logger, level);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/log4j/LoggingExceptionConcatenation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.apache.logging.log4j.Logger;
21 | import org.openrewrite.java.template.RecipeDescriptor;
22 |
23 | @RecipeDescriptor(
24 | name = "Log exceptions as parameters rather than as string concatenations",
25 | description = "By using the exception as another parameter you get the whole stack trace."
26 | )
27 | public class LoggingExceptionConcatenation {
28 |
29 | @BeforeTemplate
30 | void before(Logger logger, String s, Exception e) {
31 | logger.error(s + e);
32 | }
33 |
34 | @AfterTemplate
35 | void after(Logger logger, String s, Exception e) {
36 | logger.error(s, e);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/log4j/PrependRandomName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import com.fasterxml.jackson.annotation.JsonIgnore;
19 | import org.kohsuke.randname.RandomNameGenerator;
20 | import org.openrewrite.ExecutionContext;
21 | import org.openrewrite.Preconditions;
22 | import org.openrewrite.Recipe;
23 | import org.openrewrite.TreeVisitor;
24 | import org.openrewrite.java.JavaIsoVisitor;
25 | import org.openrewrite.java.MethodMatcher;
26 | import org.openrewrite.java.search.UsesMethod;
27 | import org.openrewrite.java.tree.J;
28 | import org.openrewrite.java.tree.JavaType;
29 |
30 | public class PrependRandomName extends Recipe {
31 | private static final MethodMatcher logStatement = new MethodMatcher("org.apache.log4j.Category *(Object, ..)");
32 |
33 | private final int seed;
34 |
35 | @JsonIgnore
36 | private transient final RandomNameGenerator randomName;
37 |
38 | public PrependRandomName(int seed) {
39 | this.seed = seed;
40 | randomName = new RandomNameGenerator(seed);
41 | }
42 |
43 | @Override
44 | public String getDisplayName() {
45 | return "Prepend a random name to each Log4J statement";
46 | }
47 |
48 | @Override
49 | public String getDescription() {
50 | return "To make finding the callsite of a logging statement easier in code search.";
51 | }
52 |
53 | @Override
54 | public TreeVisitor, ExecutionContext> getVisitor() {
55 | return Preconditions.check(new UsesMethod<>(logStatement), new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NullMarked
17 | @NonNullFields
18 | package org.openrewrite.java.logging.log4j;
19 |
20 | import org.jspecify.annotations.NullMarked;
21 | import org.openrewrite.internal.lang.NonNullFields;
22 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/logback/ConfigureLoggerLevel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.openrewrite.*;
21 | import org.openrewrite.internal.ListUtils;
22 | import org.openrewrite.xml.XPathMatcher;
23 | import org.openrewrite.xml.XmlIsoVisitor;
24 | import org.openrewrite.xml.tree.Content;
25 | import org.openrewrite.xml.tree.Xml;
26 |
27 | import java.util.List;
28 |
29 | @Value
30 | @EqualsAndHashCode(callSuper = false)
31 | public class ConfigureLoggerLevel extends Recipe {
32 |
33 | @Override
34 | public String getDisplayName() {
35 | return "Configure logback logger level";
36 | }
37 |
38 | @Override
39 | public String getDescription() {
40 | return "Within logback.xml configuration files sets the specified log level for a particular class. " +
41 | "Will not create a logback.xml if one does not already exist.";
42 | }
43 |
44 | @Option(displayName = "Class name",
45 | description = "The fully qualified class name to configure the log level for",
46 | example = "com.example.MyClass")
47 | String className;
48 |
49 | @Option(displayName = "Log level",
50 | description = "The log level to set for the class",
51 | valid = {"trace", "debug", "info", "warn", "error", "off"},
52 | example = "off")
53 | LogLevel logLevel;
54 |
55 | public enum LogLevel {
56 | trace,
57 | debug,
58 | info,
59 | warn,
60 | error,
61 | off
62 | }
63 |
64 | @Override
65 | public TreeVisitor, ExecutionContext> getVisitor() {
66 | return Preconditions.check(new FindSourceFiles("**/logback.xml"), new XmlIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import org.openrewrite.*;
19 | import org.openrewrite.internal.ListUtils;
20 | import org.openrewrite.java.*;
21 | import org.openrewrite.java.search.UsesType;
22 | import org.openrewrite.java.tree.J;
23 | import org.openrewrite.java.tree.JavaType;
24 | import org.openrewrite.java.tree.TypeUtils;
25 |
26 | public class Log4jAppenderToLogback extends Recipe {
27 | @Override
28 | public String getDisplayName() {
29 | return "Migrate Log4j 2.x Appender to logback-classic equivalents";
30 | }
31 |
32 | @Override
33 | public String getDescription() {
34 | return "Migrates custom Log4j 2.x Appender components to `logback-classic`. This recipe operates on the following assumptions: " +
35 | "1.) The contents of the `append()` method remains unchanged. " +
36 | "2.) The `requiresLayout()` method is not used in logback and can be removed. " +
37 | "3.) In logback, the `stop()` method is the equivalent of log4j's close() method. " +
38 | "For more details, see this page from logback: [`Migration from log4j`](http://logback.qos.ch/manual/migrationFromLog4j.html).";
39 | }
40 |
41 | @Override
42 | public TreeVisitor, ExecutionContext> getVisitor() {
43 | return Preconditions.check(new UsesType<>("org.apache.log4j.AppenderSkeleton", null), new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import org.openrewrite.*;
19 | import org.openrewrite.internal.ListUtils;
20 | import org.openrewrite.java.*;
21 | import org.openrewrite.java.search.UsesType;
22 | import org.openrewrite.java.tree.J;
23 | import org.openrewrite.java.tree.JavaType;
24 | import org.openrewrite.java.tree.TypeUtils;
25 |
26 | import java.time.Duration;
27 |
28 | import static java.util.Objects.requireNonNull;
29 |
30 | public class Log4jLayoutToLogback extends Recipe {
31 | @Override
32 | public String getDisplayName() {
33 | return "Migrate Log4j 2.x Layout to logback-classic equivalents";
34 | }
35 |
36 | @Override
37 | public String getDescription() {
38 | return "Migrates custom Log4j 2.x Layout components to `logback-classic`. This recipe operates on the following assumptions: " +
39 | "1. A logback-classic layout must extend the `LayoutBase
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NullMarked
17 | @NonNullFields
18 | package org.openrewrite.java.logging.logback;
19 |
20 | import org.jspecify.annotations.NullMarked;
21 | import org.openrewrite.internal.lang.NonNullFields;
22 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NullMarked
17 | @NonNullFields
18 | package org.openrewrite.java.logging;
19 |
20 | import org.jspecify.annotations.NullMarked;
21 | import org.openrewrite.internal.lang.NonNullFields;
22 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/slf4j/ChangeLogLevel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Value;
20 | import org.jspecify.annotations.Nullable;
21 | import org.openrewrite.*;
22 | import org.openrewrite.internal.StringUtils;
23 | import org.openrewrite.java.ChangeMethodName;
24 | import org.openrewrite.java.JavaIsoVisitor;
25 | import org.openrewrite.java.MethodMatcher;
26 | import org.openrewrite.java.search.UsesMethod;
27 | import org.openrewrite.java.tree.Expression;
28 | import org.openrewrite.java.tree.J;
29 |
30 | import java.util.List;
31 |
32 | @Value
33 | @EqualsAndHashCode(callSuper = false)
34 | public class ChangeLogLevel extends Recipe {
35 |
36 | @Override
37 | public String getDisplayName() {
38 | return "Change SLF4J log level";
39 | }
40 |
41 | @Override
42 | public String getDescription() {
43 | return "Change the log level of SLF4J log statements.";
44 | }
45 |
46 | @Option(displayName = "From",
47 | description = "The log level to change from.",
48 | example = "INFO")
49 | Level from;
50 |
51 | @Option(displayName = "To",
52 | description = "The log level to change to.",
53 | example = "DEBUG")
54 | Level to;
55 |
56 | @Option(displayName = "Starts with",
57 | description = "Only change log statements that start with this string. When omitted all log statements of " +
58 | "the specified level are changed.",
59 | example = "LaunchDarkly",
60 | required = false)
61 | @Nullable
62 | String startsWith;
63 |
64 | public enum Level {
65 | TRACE,
66 | DEBUG,
67 | INFO,
68 | WARN,
69 | ERROR
70 | }
71 |
72 | @Override
73 | public TreeVisitor, ExecutionContext> getVisitor() {
74 | String methodPattern = "org.slf4j.Logger " + from.name().toLowerCase() + "(..)";
75 | return Preconditions.check(new UsesMethod<>(methodPattern), new JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.openrewrite.java.template.RecipeDescriptor;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import java.util.logging.Logger;
24 |
25 | @RecipeDescriptor(
26 | name = "Replace JUL Logger creation with SLF4J LoggerFactory",
27 | description = "Replace calls to `Logger.getLogger` with `LoggerFactory.getLogger`."
28 | )
29 | public class JulGetLoggerToLoggerFactory {
30 | @RecipeDescriptor(
31 | name = "Replace JUL `Logger.getLogger(Some.class.getName())` with SLF4J's `LoggerFactory.getLogger(Some.class)`",
32 | description = "Replace calls to `java.util.logging.Logger.getLogger(Some.class.getName())` with `org.slf4j.LoggerFactory.getLogger(Some.class)`."
33 | )
34 | public static class GetLoggerClassNameToLoggerFactory {
35 | @BeforeTemplate
36 | Logger before(Class> clazz) {
37 | return Logger.getLogger(clazz.getName());
38 | }
39 |
40 | @AfterTemplate
41 | org.slf4j.Logger after(Class> clazz) {
42 | return LoggerFactory.getLogger(clazz);
43 | }
44 | }
45 |
46 | @RecipeDescriptor(
47 | name = "Replace JUL `Logger.getLogger(Some.class.getCanonicalName())` with SLF4J's `LoggerFactory.getLogger(Some.class)`",
48 | description = "Replace calls to `java.util.logging.Logger.getLogger(Some.class.getCanonicalName())` with `org.slf4j.LoggerFactory.getLogger(Some.class)`."
49 | )
50 | public static class GetLoggerClassCanonicalNameToLoggerFactory {
51 | @BeforeTemplate
52 | Logger before(Class> clazz) {
53 | return Logger.getLogger(clazz.getCanonicalName());
54 | }
55 |
56 | @AfterTemplate
57 | org.slf4j.Logger after(Class> clazz) {
58 | return LoggerFactory.getLogger(clazz);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/slf4j/JulIsLoggableToIsEnabled.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.openrewrite.java.template.RecipeDescriptor;
21 |
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 |
25 | @RecipeDescriptor(
26 | name = "Replace JUL active Level check with corresponding SLF4J method calls",
27 | description = "Replace calls to `Logger.isLoggable(Level)` with the corresponding SLF4J method calls."
28 | )
29 | public class JulIsLoggableToIsEnabled {
30 | @RecipeDescriptor(
31 | name = "Replace JUL `Logger.isLoggable(Level.ALL)` with SLF4J's `Logger.isTraceEnabled`",
32 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.ALL)` with `org.slf4j.Logger.isTraceEnabled()`."
33 | )
34 | public static class LoggerIsLoggableLevelAll {
35 | @BeforeTemplate
36 | boolean before(Logger logger) {
37 | return logger.isLoggable(Level.ALL);
38 | }
39 |
40 | @AfterTemplate
41 | boolean after(org.slf4j.Logger logger) {
42 | return logger.isTraceEnabled();
43 | }
44 | }
45 |
46 | @RecipeDescriptor(
47 | name = "Replace JUL `Logger.isLoggable(Level.FINEST)` with SLF4J's `Logger.isTraceEnabled`",
48 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.FINEST)` with `org.slf4j.Logger.isTraceEnabled()`."
49 | )
50 | public static class LoggerIsLoggableLevelFinest {
51 | @BeforeTemplate
52 | boolean before(Logger logger) {
53 | return logger.isLoggable(Level.FINEST);
54 | }
55 |
56 | @AfterTemplate
57 | boolean after(org.slf4j.Logger logger) {
58 | return logger.isTraceEnabled();
59 | }
60 | }
61 |
62 | @RecipeDescriptor(
63 | name = "Replace JUL `Logger.isLoggable(Level.FINER)` with SLF4J's `Logger.isTraceEnabled()`",
64 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.FINER)` with `org.slf4j.Logger.isTraceEnabled()`."
65 | )
66 | public static class LoggerIsLoggableLevelFiner {
67 | @BeforeTemplate
68 | boolean before(Logger logger) {
69 | return logger.isLoggable(Level.FINER);
70 | }
71 |
72 | @AfterTemplate
73 | boolean after(org.slf4j.Logger logger) {
74 | return logger.isTraceEnabled();
75 | }
76 | }
77 |
78 | @RecipeDescriptor(
79 | name = "Replace JUL `Logger.isLoggable(Level.FINE)` with SLF4J's `Logger.isDebugEnabled()`",
80 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.FINE)` with `org.slf4j.Logger.isDebugEnabled()`."
81 | )
82 | public static class LoggerIsLoggableLevelFine {
83 | @BeforeTemplate
84 | boolean before(Logger logger) {
85 | return logger.isLoggable(Level.FINE);
86 | }
87 |
88 | @AfterTemplate
89 | boolean after(org.slf4j.Logger logger) {
90 | return logger.isDebugEnabled();
91 | }
92 | }
93 |
94 | @RecipeDescriptor(
95 | name = "Replace JUL `Logger.isLoggable(Level.CONFIG)` with SLF4J's `Logger.isInfoEnabled()`",
96 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.CONFIG)` with `org.slf4j.Logger.isInfoEnabled()`."
97 | )
98 | public static class LoggerIsLoggableLevelConfig {
99 | @BeforeTemplate
100 | boolean before(Logger logger) {
101 | return logger.isLoggable(Level.CONFIG);
102 | }
103 |
104 | @AfterTemplate
105 | boolean after(org.slf4j.Logger logger) {
106 | return logger.isInfoEnabled();
107 | }
108 | }
109 |
110 | @RecipeDescriptor(
111 | name = "Replace JUL `Logger.isLoggable(Level.INFO)` with SLF4J's `Logger.isInfoEnabled()`",
112 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.INFO)` with `org.slf4j.Logger.isInfoEnabled()`."
113 | )
114 | public static class LoggerIsLoggableLevelInfo {
115 | @BeforeTemplate
116 | boolean before(Logger logger) {
117 | return logger.isLoggable(Level.INFO);
118 | }
119 |
120 | @AfterTemplate
121 | boolean after(org.slf4j.Logger logger) {
122 | return logger.isInfoEnabled();
123 | }
124 | }
125 |
126 | @RecipeDescriptor(
127 | name = "Replace JUL `Logger.isLoggable(Level.WARNING)` with SLF4J's `Logger.isWarnEnabled()`",
128 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.WARNING)` with `org.slf4j.Logger.isWarnEnabled()`."
129 | )
130 | public static class LoggerIsLoggableLevelWarning {
131 | @BeforeTemplate
132 | boolean before(Logger logger) {
133 | return logger.isLoggable(Level.WARNING);
134 | }
135 |
136 | @AfterTemplate
137 | boolean after(org.slf4j.Logger logger) {
138 | return logger.isWarnEnabled();
139 | }
140 | }
141 |
142 | @RecipeDescriptor(
143 | name = "Replace JUL `Logger.isLoggable(Level.SEVERE)` with SLF4J's `Logger.isErrorEnabled()`",
144 | description = "Replace calls to `java.util.logging.Logger.isLoggable(Level.SEVERE)` with `org.slf4j.Logger.isErrorEnabled()`."
145 | )
146 | public static class LoggerIsLoggableLevelSevere {
147 | @BeforeTemplate
148 | boolean before(Logger logger) {
149 | return logger.isLoggable(Level.SEVERE);
150 | }
151 |
152 | @AfterTemplate
153 | boolean after(org.slf4j.Logger logger) {
154 | return logger.isErrorEnabled();
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/slf4j/JulLevelAllToTrace.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.openrewrite.java.template.RecipeDescriptor;
21 |
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 |
25 | @RecipeDescriptor(
26 | name = "Replace JUL `Level.ALL` logging with SLF4J's trace level",
27 | description = "Replace `java.util.logging.Logger#log(Level.ALL, String)` with `org.slf4j.Logger#trace(String)`."
28 | )
29 | public class JulLevelAllToTrace {
30 | @BeforeTemplate
31 | void before(Logger logger, String message) {
32 | logger.log(Level.ALL, message);
33 | }
34 |
35 | @AfterTemplate
36 | void after(org.slf4j.Logger logger, String message) {
37 | logger.trace(message);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/slf4j/JulParameterizedArguments.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.jspecify.annotations.Nullable;
19 | import org.openrewrite.ExecutionContext;
20 | import org.openrewrite.Preconditions;
21 | import org.openrewrite.Recipe;
22 | import org.openrewrite.TreeVisitor;
23 | import org.openrewrite.java.JavaIsoVisitor;
24 | import org.openrewrite.java.JavaParser;
25 | import org.openrewrite.java.JavaTemplate;
26 | import org.openrewrite.java.MethodMatcher;
27 | import org.openrewrite.java.search.UsesMethod;
28 | import org.openrewrite.java.tree.*;
29 | import org.openrewrite.marker.Markers;
30 |
31 | import java.util.ArrayList;
32 | import java.util.Collections;
33 | import java.util.List;
34 | import java.util.Objects;
35 | import java.util.regex.Matcher;
36 | import java.util.regex.Pattern;
37 |
38 | import static org.openrewrite.Tree.randomId;
39 |
40 | public class JulParameterizedArguments extends Recipe {
41 | private static final MethodMatcher METHOD_MATCHER_PARAM = new MethodMatcher("java.util.logging.Logger log(java.util.logging.Level, java.lang.String, java.lang.Object)");
42 | private static final MethodMatcher METHOD_MATCHER_ARRAY = new MethodMatcher("java.util.logging.Logger log(java.util.logging.Level, java.lang.String, java.lang.Object[])");
43 |
44 | @Override
45 | public String getDisplayName() {
46 | return "Replace parameterized JUL level call with corresponding SLF4J method calls";
47 | }
48 |
49 | @Override
50 | public String getDescription() {
51 | return "Replace calls to parameterized `Logger.log(Level,String,…)` call with the corresponding slf4j method calls transforming the formatter and parameter lists.";
52 | }
53 |
54 | @Override
55 | public TreeVisitor, ExecutionContext> getVisitor() {
56 | return Preconditions.check(Preconditions.or(new UsesMethod<>(METHOD_MATCHER_PARAM), new UsesMethod<>(METHOD_MATCHER_ARRAY)), new JulParameterizedToSlf4jVisitor());
57 | }
58 |
59 | private static class JulParameterizedToSlf4jVisitor extends JavaIsoVisitor
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import com.google.errorprone.refaster.annotation.AfterTemplate;
19 | import com.google.errorprone.refaster.annotation.BeforeTemplate;
20 | import org.openrewrite.java.template.RecipeDescriptor;
21 |
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 |
25 | @RecipeDescriptor(
26 | name = "Replace JUL `log(Level, String, Throwable)` with corresponding SLF4J method calls",
27 | description = "Replace calls to `Logger.log(Level, String, Throwable)` with the corresponding SLF4J method calls."
28 | )
29 | public class JulToSlf4jSimpleCallsWithThrowable {
30 | @RecipeDescriptor(
31 | name = "Replace JUL `logger.log(Level.FINEST, String message, Throwable e)` with SLF4J's `Logger.trace(message, e)`",
32 | description = "Replace calls to `java.util.logging.Logger.log(Level.FINEST, String message, Throwable e)` with `org.slf4j.Logger.trace(message, e)`."
33 | )
34 | public static class JulToSlf4jSupplierFinest {
35 | @BeforeTemplate
36 | void before(Logger logger, String message, Throwable e) {
37 | logger.log(Level.FINEST, message, e);
38 | }
39 |
40 | @AfterTemplate
41 | void after(org.slf4j.Logger logger, String message, Throwable e) {
42 | logger.trace(message, e);
43 | }
44 | }
45 |
46 | @RecipeDescriptor(
47 | name = "Replace JUL `logger.log(Level.FINER, String message, Throwable e)` with SLF4J's `Logger.trace(message, e)`",
48 | description = "Replace calls to `java.util.logging.Logger.log(Level.FINER, String message, Throwable e)` with `org.slf4j.Logger.trace(message, e)`."
49 | )
50 | public static class JulToSlf4jSupplierFiner {
51 | @BeforeTemplate
52 | void before(Logger logger, String message, Throwable e) {
53 | logger.log(Level.FINER, message, e);
54 | }
55 |
56 | @AfterTemplate
57 | void after(org.slf4j.Logger logger, String message, Throwable e) {
58 | logger.trace(message, e);
59 | }
60 | }
61 |
62 | @RecipeDescriptor(
63 | name = "Replace JUL `logger.log(Level.FINE, String message, Throwable e)` with SLF4J's `Logger.debug(message, e)`",
64 | description = "Replace calls to `java.util.logging.Logger.log(Level.FINE, String message, Throwable e)` with `org.slf4j.Logger.debug(message, e)`."
65 | )
66 | public static class JulToSlf4jSupplierFine {
67 | @BeforeTemplate
68 | void before(Logger logger, String message, Throwable e) {
69 | logger.log(Level.FINE, message, e);
70 | }
71 |
72 | @AfterTemplate
73 | void after(org.slf4j.Logger logger, String message, Throwable e) {
74 | logger.debug(message, e);
75 | }
76 | }
77 |
78 | @RecipeDescriptor(
79 | name = "Replace JUL `logger.log(Level.CONFIG, String message, Throwable e)` with SLF4J's `Logger.info(message, e)`",
80 | description = "Replace calls to `java.util.logging.Logger.log(Level.CONFIG, String message, Throwable e)` with `org.slf4j.Logger.info(message, e)`."
81 | )
82 | public static class JulToSlf4jSupplierConfig {
83 | @BeforeTemplate
84 | void before(Logger logger, String message, Throwable e) {
85 | logger.log(Level.CONFIG, message, e);
86 | }
87 |
88 | @AfterTemplate
89 | void after(org.slf4j.Logger logger, String message, Throwable e) {
90 | logger.info(message, e);
91 | }
92 | }
93 |
94 | @RecipeDescriptor(
95 | name = "Replace JUL `logger.log(Level.INFO, String message, Throwable e)` with SLF4J's `Logger.info(message, e)`",
96 | description = "Replace calls to `java.util.logging.Logger.log(Level.INFO, String message, Throwable e)` with `org.slf4j.Logger.info(message, e)`."
97 | )
98 | public static class JulToSlf4jSupplierInfo {
99 | @BeforeTemplate
100 | void before(Logger logger, String message, Throwable e) {
101 | logger.log(Level.INFO, message, e);
102 | }
103 |
104 | @AfterTemplate
105 | void after(org.slf4j.Logger logger, String message, Throwable e) {
106 | logger.info(message, e);
107 | }
108 | }
109 |
110 | @RecipeDescriptor(
111 | name = "Replace JUL `logger.log(Level.WARNING, String message, Throwable e)` with SLF4J's `Logger.warn(message, e)`",
112 | description = "Replace calls to `java.util.logging.Logger.log(Level.WARNING, String message, Throwable e)` with `org.slf4j.Logger.warn(message, e)`."
113 | )
114 | public static class JulToSlf4jSupplierWarning {
115 | @BeforeTemplate
116 | void before(Logger logger, String message, Throwable e) {
117 | logger.log(Level.WARNING, message, e);
118 | }
119 |
120 | @AfterTemplate
121 | void after(org.slf4j.Logger logger, String message, Throwable e) {
122 | logger.warn(message, e);
123 | }
124 | }
125 |
126 | @RecipeDescriptor(
127 | name = "Replace JUL `logger.log(Level.SEVERE, String message, Throwable e)` with SLF4J's `Logger.error(message, e)`",
128 | description = "Replace calls to `java.util.logging.Logger.log(Level.SEVERE, String message, Throwable e)` with `org.slf4j.Logger.error(message, e)`."
129 | )
130 | public static class JulToSlf4jSupplierSevere {
131 | @BeforeTemplate
132 | void before(Logger logger, String message, Throwable e) {
133 | logger.log(Level.SEVERE, message, e);
134 | }
135 |
136 | @AfterTemplate
137 | void after(org.slf4j.Logger logger, String message, Throwable e) {
138 | logger.error(message, e);
139 | }
140 | }
141 |
142 | @RecipeDescriptor(
143 | name = "Replace JUL `logger.log(Level.ALL, String message, Throwable e)` with SLF4J's `Logger.trace(message, e)`",
144 | description = "Replace calls to `java.util.logging.Logger.log(Level.ALL, String message, Throwable e)` with `org.slf4j.Logger.trace(message, e)`."
145 | )
146 | public static class JulToSlf4jSupplierAll {
147 | @BeforeTemplate
148 | void before(Logger logger, String message, Throwable e) {
149 | logger.log(Level.ALL, message, e);
150 | }
151 |
152 | @AfterTemplate
153 | void after(org.slf4j.Logger logger, String message, Throwable e) {
154 | logger.trace(message, e);
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/org/openrewrite/java/logging/slf4j/LoggersNamedForEnclosingClass.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.openrewrite.ExecutionContext;
19 | import org.openrewrite.Preconditions;
20 | import org.openrewrite.Recipe;
21 | import org.openrewrite.TreeVisitor;
22 | import org.openrewrite.java.JavaIsoVisitor;
23 | import org.openrewrite.java.JavaTemplate;
24 | import org.openrewrite.java.JavadocVisitor;
25 | import org.openrewrite.java.MethodMatcher;
26 | import org.openrewrite.java.search.UsesType;
27 | import org.openrewrite.java.tree.Expression;
28 | import org.openrewrite.java.tree.J;
29 | import org.openrewrite.java.tree.JavaType;
30 | import org.openrewrite.java.tree.Javadoc;
31 |
32 | import java.time.Duration;
33 | import java.util.Arrays;
34 | import java.util.HashSet;
35 | import java.util.Set;
36 |
37 | public class LoggersNamedForEnclosingClass extends Recipe {
38 |
39 | private static final MethodMatcher LOGGERFACTORY_GETLOGGER = new MethodMatcher(
40 | "org.slf4j.LoggerFactory getLogger(Class)");
41 |
42 | @Override
43 | public String getDisplayName() {
44 | return "Loggers should be named for their enclosing classes";
45 | }
46 |
47 | @Override
48 | public String getDescription() {
49 | return "Ensure `LoggerFactory#getLogger(Class)` is called with the enclosing class as argument.";
50 | }
51 |
52 | @Override
53 | public Duration getEstimatedEffortPerOccurrence() {
54 | return Duration.ofMinutes(1);
55 | }
56 |
57 | @Override
58 | public Set
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.openrewrite.ExecutionContext;
19 | import org.openrewrite.Preconditions;
20 | import org.openrewrite.Recipe;
21 | import org.openrewrite.TreeVisitor;
22 | import org.openrewrite.internal.ListUtils;
23 | import org.openrewrite.internal.StringUtils;
24 | import org.openrewrite.java.JavaTemplate;
25 | import org.openrewrite.java.JavaVisitor;
26 | import org.openrewrite.java.MethodMatcher;
27 | import org.openrewrite.java.search.UsesMethod;
28 | import org.openrewrite.java.tree.Expression;
29 | import org.openrewrite.java.tree.J;
30 | import org.openrewrite.java.tree.JavaType;
31 | import org.openrewrite.java.tree.TypeUtils;
32 |
33 | import java.util.*;
34 | import java.util.regex.Pattern;
35 |
36 | public class Slf4jLogShouldBeConstant extends Recipe {
37 |
38 | private static final String SLF4J_FORMAT_SPECIFIER = "{}";
39 | private static final Pattern SLF4J_FORMAT_SPECIFIER_PATTERN = Pattern.compile("\\{}");
40 | private static final Pattern FORMAT_SPECIFIER_PATTERN = Pattern.compile("%[\\d.]*[dfscbBhHn%]");
41 |
42 | // A regular expression that matches index specifiers like '%2$s', '%1$s', etc.
43 | private static final Pattern INDEXED_FORMAT_SPECIFIER_PATTERN = Pattern.compile("%(\\d+\\$)[a-zA-Z]");
44 | private static final MethodMatcher SLF4J_LOG = new MethodMatcher("org.slf4j.Logger *(..)");
45 | private static final MethodMatcher STRING_FORMAT = new MethodMatcher("java.lang.String format(..)");
46 | private static final MethodMatcher STRING_VALUE_OF = new MethodMatcher("java.lang.String valueOf(..)");
47 | private static final MethodMatcher OBJECT_TO_STRING = new MethodMatcher("java.lang.Object toString()");
48 |
49 | @Override
50 | public String getDisplayName() {
51 | return "SLF4J logging statements should begin with constants";
52 | }
53 |
54 | @Override
55 | public String getDescription() {
56 | return "Logging statements shouldn't begin with `String#format`, calls to `toString()`, etc.";
57 | }
58 |
59 | @Override
60 | public Set
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NullMarked
17 | @NonNullFields
18 | package org.openrewrite.java.logging.slf4j;
19 |
20 | import org.jspecify.annotations.NullMarked;
21 | import org.openrewrite.internal.lang.NonNullFields;
22 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/rewrite/category.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 the original author or authors.
3 | #
4 | # Licensed under the Moderne Source Available License (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://docs.moderne.io/licensing/moderne-source-available-license
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ---
18 | type: specs.openrewrite.org/v1beta/category
19 | name: Logging
20 | packageName: org.openrewrite.java.logging
21 | description: Enforce logging best practices and migrate between logging frameworks.
22 | ---
23 | type: specs.openrewrite.org/v1beta/category
24 | name: Logback
25 | packageName: org.openrewrite.java.logging.logback
26 | description: Recipes related to [`logback`](http://logback.qos.ch/documentation.html).
27 | ---
28 | type: specs.openrewrite.org/v1beta/category
29 | name: SLF4J
30 | packageName: org.openrewrite.java.logging.slf4j
31 | description: Recipes related to [Simple Logging Facade for Java (`SLF4J`)](http://www.slf4j.org/).
32 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/rewrite/classpath.tsv.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openrewrite/rewrite-logging-frameworks/1e14228375c9b918d5f82da7737d574b8eb111d7/src/main/resources/META-INF/rewrite/classpath.tsv.zip
--------------------------------------------------------------------------------
/src/main/resources/META-INF/rewrite/logback.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 the original author or authors.
3 | #
4 | # Licensed under the Moderne Source Available License (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://docs.moderne.io/licensing/moderne-source-available-license
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ---
18 | type: specs.openrewrite.org/v1beta/recipe
19 | name: org.openrewrite.java.logging.logback.Log4jToLogback
20 | displayName: Migrate Log4j 2.x to Logback
21 | description: Migrates usage of Apache Log4j 2.x to using `logback` as an SLF4J implementation directly. Note, this currently does not modify `log4j.properties` files.
22 | tags:
23 | - logging
24 | - log4j
25 | - logback
26 | recipeList:
27 | ## Start by moving Log4J to the abstract of SLF4J, then having SLF4J implementation dependencies are on logback.
28 | - org.openrewrite.java.logging.slf4j.Log4jToSlf4j
29 | - org.openrewrite.java.logging.logback.Log4jAppenderToLogback
30 | - org.openrewrite.java.logging.logback.Log4jLayoutToLogback
31 | - org.openrewrite.java.dependencies.AddDependency:
32 | groupId: ch.qos.logback
33 | artifactId: logback-core
34 | version: latest.release
35 | onlyIfUsing: org.apache.logging.log4j.*
36 | - org.openrewrite.java.dependencies.AddDependency:
37 | groupId: ch.qos.logback
38 | artifactId: logback-classic
39 | version: latest.release
40 | onlyIfUsing: org.apache.logging.log4j.*
41 | - org.openrewrite.java.dependencies.AddDependency:
42 | groupId: org.slf4j
43 | artifactId: slf4j-api
44 | version: latest.release
45 | onlyIfUsing: org.apache.logging.log4j.*
46 | - org.openrewrite.java.dependencies.RemoveDependency:
47 | groupId: org.apache.logging.log4j
48 | artifactId: log4j-*
49 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/CatchBlockLogLevelTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.java.JavaParser;
21 | import org.openrewrite.test.RecipeSpec;
22 | import org.openrewrite.test.RewriteTest;
23 |
24 | import static org.openrewrite.java.Assertions.java;
25 |
26 | @SuppressWarnings("RedundantSlf4jDefinition")
27 | class CatchBlockLogLevelTest implements RewriteTest {
28 |
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipe(new CatchBlockLogLevel());
32 | }
33 |
34 | @DocumentExample
35 | @Test
36 | void log4j1() {
37 | rewriteRun(
38 | spec -> spec.parser(JavaParser.fromJavaVersion().classpath("log4j")),
39 | //language=java
40 | java(
41 | """
42 | import org.apache.log4j.Logger;
43 |
44 | class A {
45 | Logger log = Logger.getLogger(A.class);
46 | void test() {
47 | try {
48 | log.info("unchanged");
49 | throw new RuntimeException();
50 | } catch (Exception e) {
51 | log.info("Some context");
52 | log.info("Caught exception", e);
53 | }
54 | }
55 | }
56 | """,
57 | """
58 | import org.apache.log4j.Logger;
59 |
60 | class A {
61 | Logger log = Logger.getLogger(A.class);
62 | void test() {
63 | try {
64 | log.info("unchanged");
65 | throw new RuntimeException();
66 | } catch (Exception e) {
67 | log.warn("Some context");
68 | log.error("Caught exception", e);
69 | }
70 | }
71 | }
72 | """
73 | )
74 | );
75 | }
76 |
77 | @Test
78 | void log4j2() {
79 | rewriteRun(
80 | spec -> spec.parser(JavaParser.fromJavaVersion().classpath("log4j-core", "log4j-api")),
81 | //language=java
82 | java(
83 | """
84 | import org.apache.logging.log4j.LogManager;
85 | import org.apache.logging.log4j.Logger;
86 |
87 | class A {
88 | Logger log = LogManager.getLogger(A.class);
89 | void test() {
90 | try {
91 | log.info("unchanged");
92 | throw new RuntimeException();
93 | } catch (Exception e) {
94 | log.info("Some context");
95 | log.info("Caught exception", e);
96 | }
97 | }
98 | }
99 | """,
100 | """
101 | import org.apache.logging.log4j.LogManager;
102 | import org.apache.logging.log4j.Logger;
103 |
104 | class A {
105 | Logger log = LogManager.getLogger(A.class);
106 | void test() {
107 | try {
108 | log.info("unchanged");
109 | throw new RuntimeException();
110 | } catch (Exception e) {
111 | log.warn("Some context");
112 | log.error("Caught exception", e);
113 | }
114 | }
115 | }
116 | """
117 | )
118 | );
119 | }
120 |
121 | @Test
122 | void slf4j() {
123 | rewriteRun(
124 | spec -> spec.parser(JavaParser.fromJavaVersion().classpath("slf4j-api")),
125 | //language=java
126 | java(
127 | """
128 | import org.slf4j.Logger;
129 | import org.slf4j.LoggerFactory;
130 |
131 | class A {
132 | Logger log = LoggerFactory.getLogger(A.class);
133 | void test() {
134 | try {
135 | log.info("unchanged");
136 | throw new RuntimeException();
137 | } catch (Exception e) {
138 | log.info("Some context");
139 | log.info("Caught exception", e);
140 | }
141 | }
142 | }
143 | """,
144 | """
145 | import org.slf4j.Logger;
146 | import org.slf4j.LoggerFactory;
147 |
148 | class A {
149 | Logger log = LoggerFactory.getLogger(A.class);
150 | void test() {
151 | try {
152 | log.info("unchanged");
153 | throw new RuntimeException();
154 | } catch (Exception e) {
155 | log.warn("Some context");
156 | log.error("Caught exception", e);
157 | }
158 | }
159 | }
160 | """
161 | )
162 | );
163 | }
164 |
165 | @Test
166 | void logbackClassic() {
167 | rewriteRun(
168 | spec -> spec.parser(JavaParser.fromJavaVersion().classpath("slf4j-api", "logback-classic", "logback-core")),
169 | //language=java
170 | java(
171 | """
172 | import ch.qos.logback.classic.Logger;
173 | import org.slf4j.LoggerFactory;
174 |
175 | class A {
176 | Logger log = (Logger) LoggerFactory.getLogger(A.class);
177 | void test() {
178 | try {
179 | log.info("unchanged");
180 | throw new RuntimeException();
181 | } catch (Exception e) {
182 | log.info("Some context");
183 | log.info("Caught exception", e);
184 | }
185 | }
186 | }
187 | """,
188 | """
189 | import ch.qos.logback.classic.Logger;
190 | import org.slf4j.LoggerFactory;
191 |
192 | class A {
193 | Logger log = (Logger) LoggerFactory.getLogger(A.class);
194 | void test() {
195 | try {
196 | log.info("unchanged");
197 | throw new RuntimeException();
198 | } catch (Exception e) {
199 | log.warn("Some context");
200 | log.error("Caught exception", e);
201 | }
202 | }
203 | }
204 | """
205 | )
206 | );
207 |
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/ChangeLoggersToPrivateTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.test.RecipeSpec;
21 | import org.openrewrite.test.RewriteTest;
22 |
23 | import static org.openrewrite.java.Assertions.java;
24 |
25 | class ChangeLoggersToPrivateTest implements RewriteTest {
26 |
27 | @Override
28 | public void defaults(RecipeSpec spec) {
29 | spec.recipe(new ChangeLoggersToPrivate());
30 | }
31 |
32 | @DocumentExample
33 | @Test
34 | void changePublicSlf4jLoggerPrivate() {
35 | rewriteRun(
36 | //language=java
37 | java(
38 | """
39 | import org.slf4j.Logger;
40 | import org.slf4j.LoggerFactory;
41 |
42 | class Test {
43 | public static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
44 | }
45 | """,
46 | """
47 | import org.slf4j.Logger;
48 | import org.slf4j.LoggerFactory;
49 |
50 | class Test {
51 | private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
52 | }
53 | """
54 | )
55 | );
56 | }
57 |
58 | @Test
59 | void changePublicLog4j2LoggerPrivate() {
60 | rewriteRun(
61 | //language=java
62 | java(
63 | """
64 | import org.apache.logging.log4j.Logger;
65 | import org.apache.logging.log4j.LogManager;
66 |
67 | class Test {
68 | public static final Logger LOGGER = LogManager.getLogger(Test.class);
69 | }
70 | """,
71 | """
72 | import org.apache.logging.log4j.Logger;
73 | import org.apache.logging.log4j.LogManager;
74 |
75 | class Test {
76 | private static final Logger LOGGER = LogManager.getLogger(Test.class);
77 | }
78 | """
79 | )
80 | );
81 | }
82 |
83 | @Test
84 | void changeProtectedLog4jLoggerPrivate() {
85 | rewriteRun(
86 | //language=java
87 | java(
88 | """
89 | import org.apache.log4j.Logger;
90 |
91 | class Test {
92 | protected Logger log = Logger.getLogger(Test.class);
93 | }
94 | """,
95 | """
96 | import org.apache.log4j.Logger;
97 |
98 | class Test {
99 | private Logger log = Logger.getLogger(Test.class);
100 | }
101 | """
102 | )
103 | );
104 | }
105 |
106 | @Test
107 | void changeDefaultJulLoggerPrivate() {
108 | rewriteRun(
109 | //language=java
110 | java(
111 | """
112 | import java.util.logging.Logger;
113 |
114 | class Test {
115 | static final Logger LOG = Logger.getLogger(Test.class.getName());
116 | }
117 | """,
118 | """
119 | import java.util.logging.Logger;
120 |
121 | class Test {
122 | private static final Logger LOG = Logger.getLogger(Test.class.getName());
123 | }
124 | """
125 | )
126 | );
127 | }
128 |
129 | @Test
130 | void keepExistingPrivateLogger() {
131 | rewriteRun(
132 | //language=java
133 | java(
134 | """
135 | import org.slf4j.Logger;
136 | import org.slf4j.LoggerFactory;
137 |
138 | class Test {
139 | private final Logger logger = LoggerFactory.getLogger(Test.class);
140 | }
141 | """
142 | )
143 | );
144 | }
145 |
146 | @Test
147 | void notALoggerField() {
148 | rewriteRun(
149 | //language=java
150 | java(
151 | """
152 | class Test {
153 | public String name = "test";
154 | protected int count = 0;
155 | }
156 | """
157 | )
158 | );
159 | }
160 |
161 | @Test
162 | void loggerInInterfaceShouldNotChange() {
163 | rewriteRun(
164 | //language=java
165 | java(
166 | """
167 | import org.slf4j.Logger;
168 | import org.slf4j.LoggerFactory;
169 |
170 | interface Constants {
171 | Logger logger = LoggerFactory.getLogger(Constants.class);
172 | }
173 | """
174 | )
175 | );
176 | }
177 |
178 | @Test
179 | void localVariableLoggerShouldNotChange() {
180 | rewriteRun(
181 | //language=java
182 | java(
183 | """
184 | import org.slf4j.Logger;
185 | import org.slf4j.LoggerFactory;
186 |
187 | class Test {
188 | public void doSomething() {
189 | Logger localLog = LoggerFactory.getLogger(Test.class);
190 | localLog.info("Hello");
191 | }
192 | }
193 | """
194 | )
195 | );
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/SystemOutToLoggingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.Issue;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 | import org.openrewrite.test.TypeValidation;
26 |
27 | import static org.openrewrite.java.Assertions.java;
28 |
29 | class SystemOutToLoggingTest implements RewriteTest {
30 |
31 | @Override
32 | public void defaults(RecipeSpec spec) {
33 | spec.parser(JavaParser.fromJavaVersion()
34 | .classpathFromResources(new InMemoryExecutionContext(), "slf4j-api-2.1.+", "lombok-1.18.+"));
35 | }
36 |
37 | @DocumentExample
38 | @Test
39 | void useSlf4j() {
40 | rewriteRun(
41 | spec -> spec.recipe(new SystemOutToLogging(null, "LOGGER", null, "debug")),
42 | //language=java
43 | java(
44 | """
45 | import org.slf4j.Logger;
46 | class Test {
47 | int n;
48 | Logger logger;
49 |
50 | void test() {
51 | System.out.println("Oh " + n + " no");
52 | }
53 | }
54 | """,
55 | """
56 | import org.slf4j.Logger;
57 | class Test {
58 | int n;
59 | Logger logger;
60 |
61 | void test() {
62 | logger.debug("Oh {} no", n);
63 | }
64 | }
65 | """
66 | )
67 | );
68 | }
69 |
70 | @Test
71 | void inRunnable() {
72 | rewriteRun(
73 | spec -> spec.recipe(new SystemOutToLogging(null, "LOGGER", null, "debug")),
74 | //language=java
75 | java(
76 | """
77 | import org.slf4j.Logger;
78 | class Test {
79 | Logger logger;
80 |
81 | void test() {
82 | Runnable r = () -> System.out.println("single");
83 | }
84 | }
85 | """,
86 | """
87 | import org.slf4j.Logger;
88 | class Test {
89 | Logger logger;
90 |
91 | void test() {
92 | Runnable r = () -> logger.debug("single");
93 | }
94 | }
95 | """
96 | )
97 | );
98 | }
99 |
100 | @Test
101 | @Issue("https://github.com/openrewrite/rewrite-logging-frameworks/issues/114")
102 | void supportLombokLogAnnotations() {
103 | rewriteRun(
104 | spec -> spec.recipe(new SystemOutToLogging(null, null, null, "info"))
105 | .typeValidationOptions(TypeValidation.builder().identifiers(false).build()),
106 | //language=java
107 | java(
108 | """
109 | import lombok.extern.slf4j.Slf4j;
110 | @Slf4j
111 | class Test {
112 | int n;
113 |
114 | void test() {
115 | System.out.println("Oh " + n + " no");
116 | }
117 | }
118 | """,
119 | """
120 | import lombok.extern.slf4j.Slf4j;
121 | @Slf4j
122 | class Test {
123 | int n;
124 |
125 | void test() {
126 | log.info("Oh {} no", n);
127 | }
128 | }
129 | """
130 | )
131 | );
132 | }
133 |
134 | @Test
135 | @Issue("https://github.com/openrewrite/rewrite-logging-frameworks/issues/125")
136 | void doNotDeleteFile() {
137 | rewriteRun(
138 | spec -> spec
139 | .recipe(new SystemOutToLogging(true, "log", "JUL", null)),
140 | //language=java
141 | java(
142 | """
143 | class Foo {
144 | void bar() {
145 | System.out.println("Test");
146 | }
147 | }
148 | """,
149 | """
150 | import java.util.logging.Level;
151 | import java.util.logging.LogManager;
152 | import java.util.logging.Logger;
153 |
154 | class Foo {
155 | private static final Logger log = LogManager.getLogManager().getLogger("Foo");
156 |
157 | void bar() {
158 | log.log(Level.INFO, "Test");
159 | }
160 | }
161 | """
162 | )
163 | );
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/jul/LoggerLevelArgumentToMethodTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.jul;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.test.RecipeSpec;
21 | import org.openrewrite.test.RewriteTest;
22 |
23 | import static org.openrewrite.java.Assertions.java;
24 |
25 | class LoggerLevelArgumentToMethodTest implements RewriteTest {
26 |
27 | @Override
28 | public void defaults(RecipeSpec spec) {
29 | spec.recipe(new LoggerLevelArgumentToMethodRecipes());
30 | }
31 |
32 | @DocumentExample
33 | @Test
34 | void replaceLevelArguments() {
35 | rewriteRun(
36 | //language=java
37 | java(
38 | """
39 | import java.util.logging.Level;
40 | import java.util.logging.Logger;
41 |
42 | class Test {
43 | void test(Logger logger, String message) {
44 | logger.log(Level.FINEST, message);
45 | logger.log(Level.FINER, message);
46 | logger.log(Level.FINE, message);
47 | logger.log(Level.INFO, message);
48 | logger.log(Level.WARNING, message);
49 | logger.log(Level.SEVERE, message);
50 | logger.log(Level.CONFIG, message);
51 | }
52 | }
53 | """,
54 | """
55 | import java.util.logging.Logger;
56 |
57 | class Test {
58 | void test(Logger logger, String message) {
59 | logger.finest(message);
60 | logger.finer(message);
61 | logger.fine(message);
62 | logger.info(message);
63 | logger.warning(message);
64 | logger.severe(message);
65 | logger.config(message);
66 | }
67 | }
68 | """
69 | )
70 | );
71 | }
72 |
73 | @Test
74 | void replaceLevelArgumentsWithSupplier() {
75 | rewriteRun(
76 | //language=java
77 | java(
78 | """
79 | import java.util.function.Supplier;
80 | import java.util.logging.Level;
81 | import java.util.logging.Logger;
82 |
83 | class Test {
84 | void test(Logger logger, Supplier
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 | import org.openrewrite.test.TypeValidation;
25 |
26 | import static org.openrewrite.java.Assertions.java;
27 |
28 | class CommonsLoggingToLog4jTest implements RewriteTest {
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipeFromResource("/META-INF/rewrite/log4j.yml",
32 | "org.openrewrite.java.logging.log4j.CommonsLoggingToLog4j")
33 | .parser(JavaParser.fromJavaVersion()
34 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-api-2.+", "commons-logging-1.3.+", "lombok-1.18.+"));
35 | }
36 |
37 | @DocumentExample
38 | @Test
39 | void loggerFactoryToLogManager() {
40 | // language=java
41 | rewriteRun(
42 | java(
43 | """
44 | import org.apache.commons.logging.LogFactory;
45 | import org.apache.commons.logging.Log;
46 |
47 | class Test {
48 | Log log1 = LogFactory.getLog(Test.class);
49 | Log log2 = LogFactory.getLog("Test");
50 | Log log3 = LogFactory.getFactory().getInstance(Test.class);
51 | Log log4 = LogFactory.getFactory().getInstance("Test");
52 | }
53 | """,
54 | """
55 | import org.apache.logging.log4j.LogManager;
56 | import org.apache.logging.log4j.Logger;
57 |
58 | class Test {
59 | Logger log1 = LogManager.getLogger(Test.class);
60 | Logger log2 = LogManager.getLogger("Test");
61 | Logger log3 = LogManager.getLogger(Test.class);
62 | Logger log4 = LogManager.getLogger("Test");
63 | }
64 | """
65 | )
66 | );
67 | }
68 |
69 | @Test
70 | void changeLombokLogAnnotation() {
71 | // language=java
72 | rewriteRun(
73 | spec -> spec.typeValidationOptions(TypeValidation.builder()
74 | .identifiers(false)
75 | .methodInvocations(false)
76 | .build()),
77 | java(
78 | """
79 | import lombok.extern.apachecommons.CommonsLog;
80 |
81 | @CommonsLog
82 | class Test {
83 | void method() {
84 | log.info("uh oh");
85 | }
86 | }
87 | """,
88 | """
89 | import lombok.extern.log4j.Log4j2;
90 |
91 | @Log4j2
92 | class Test {
93 | void method() {
94 | log.info("uh oh");
95 | }
96 | }
97 | """
98 | )
99 | );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/log4j/ConvertJulEnteringTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.ChangeType;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 |
26 | import static org.openrewrite.java.Assertions.java;
27 |
28 | class ConvertJulEnteringTest implements RewriteTest {
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipes(new ConvertJulEntering(),
32 | new ChangeType("java.util.logging.Logger", "org.apache.logging.log4j.Logger", true))
33 | .parser(JavaParser.fromJavaVersion()
34 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-api-2.+"));
35 | }
36 |
37 | @Test
38 | @DocumentExample
39 | void enteringToTraceEntry() {
40 | rewriteRun(
41 | // language=java
42 | java(
43 | """
44 | import java.util.logging.Logger;
45 |
46 | class Test {
47 | void method(Logger logger) {
48 | logger.entering("Test", "method");
49 | logger.entering("Test", "method", "param");
50 | logger.entering("Test", "method", new Object[]{"param1", "param2"});
51 | }
52 | }
53 | """,
54 | """
55 | import org.apache.logging.log4j.Logger;
56 |
57 | class Test {
58 | void method(Logger logger) {
59 | logger.traceEntry();
60 | logger.traceEntry(null, "param");
61 | logger.traceEntry(null, new Object[]{"param1", "param2"});
62 | }
63 | }
64 | """
65 | )
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/log4j/ConvertJulExitingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.ChangeType;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 |
26 | import static org.openrewrite.java.Assertions.java;
27 |
28 | class ConvertJulExitingTest implements RewriteTest {
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipes(new ConvertJulExiting(),
32 | new ChangeType("java.util.logging.Logger", "org.apache.logging.log4j.Logger", true))
33 | .parser(JavaParser.fromJavaVersion()
34 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-api-2.+"));
35 | }
36 |
37 | @Test
38 | @DocumentExample
39 | void exitingToTraceExit() {
40 | rewriteRun(
41 | // language=java
42 | java(
43 | """
44 | import java.util.logging.Logger;
45 |
46 | class Test {
47 | void method(Logger logger) {
48 | logger.exiting("Test", "method");
49 | logger.exiting("Test", "method", "result");
50 | }
51 | }
52 | """,
53 | """
54 | import org.apache.logging.log4j.Logger;
55 |
56 | class Test {
57 | void method(Logger logger) {
58 | logger.traceExit();
59 | logger.traceExit("result");
60 | }
61 | }
62 | """
63 | )
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/log4j/JulToLog4jTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 | import org.openrewrite.test.TypeValidation;
25 |
26 | import static org.openrewrite.java.Assertions.java;
27 |
28 | class JulToLog4jTest implements RewriteTest {
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipeFromResource("/META-INF/rewrite/log4j.yml", "org.openrewrite.java.logging.log4j.JulToLog4j")
32 | .parser(JavaParser.fromJavaVersion()
33 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-api-2.+", "lombok-1.18.+"));
34 | }
35 |
36 | @Test
37 | @DocumentExample
38 | void simpleLoggerCalls() {
39 | rewriteRun(
40 | // language=java
41 | java(
42 | """
43 | import java.util.logging.Level;
44 | import java.util.logging.Logger;
45 |
46 | class Test {
47 | void method(Logger logger) {
48 | logger.config("Hello");
49 | logger.config(() -> "Hello");
50 | logger.fine("Hello");
51 | logger.fine(() -> "Hello");
52 | logger.finer("Hello");
53 | logger.finer(() -> "Hello");
54 | logger.finest("Hello");
55 | logger.finest(() -> "Hello");
56 | logger.info("Hello");
57 | logger.info(() -> "Hello");
58 | logger.severe("Hello");
59 | logger.severe(() -> "Hello");
60 | logger.warning("Hello");
61 | logger.warning(() -> "Hello");
62 |
63 | logger.log(Level.INFO, "Hello");
64 | logger.log(Level.INFO, () -> "Hello");
65 | }
66 | }
67 | """,
68 | """
69 | import org.apache.logging.log4j.Logger;
70 |
71 | class Test {
72 | void method(Logger logger) {
73 | logger.info("Hello");
74 | logger.info(() -> "Hello");
75 | logger.debug("Hello");
76 | logger.debug(() -> "Hello");
77 | logger.trace("Hello");
78 | logger.trace(() -> "Hello");
79 | logger.trace("Hello");
80 | logger.trace(() -> "Hello");
81 | logger.info("Hello");
82 | logger.info(() -> "Hello");
83 | logger.error("Hello");
84 | logger.error(() -> "Hello");
85 | logger.warn("Hello");
86 | logger.warn(() -> "Hello");
87 |
88 | logger.info("Hello");
89 | logger.info(() -> "Hello");
90 | }
91 | }
92 | """
93 | )
94 | );
95 | }
96 |
97 | @Test
98 | void loggerToLogManager() {
99 | rewriteRun(
100 | // language=java
101 | java(
102 | """
103 | import java.util.logging.Logger;
104 |
105 | class Test {
106 | Logger log = Logger.getLogger("Test");
107 | }
108 | """,
109 | """
110 | import org.apache.logging.log4j.LogManager;
111 | import org.apache.logging.log4j.Logger;
112 |
113 | class Test {
114 | Logger log = LogManager.getLogger("Test");
115 | }
116 | """
117 | )
118 | );
119 | }
120 |
121 | @Test
122 | void changeLombokLogAnnotation() {
123 | rewriteRun(spec -> spec.typeValidationOptions(TypeValidation.builder()
124 | .identifiers(false)
125 | .methodInvocations(false)
126 | .build()),
127 | // language=java
128 | java(
129 | """
130 | import lombok.extern.java.Log;
131 |
132 | @Log
133 | class Test {
134 | void method() {
135 | log.info("uh oh");
136 | }
137 | }
138 | """,
139 | """
140 | import lombok.extern.log4j.Log4j2;
141 |
142 | @Log4j2
143 | class Test {
144 | void method() {
145 | log.info("uh oh");
146 | }
147 | }
148 | """
149 | )
150 | );
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/log4j/LoggingExceptionConcatenationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.java.JavaParser;
21 | import org.openrewrite.test.RecipeSpec;
22 | import org.openrewrite.test.RewriteTest;
23 |
24 | import static org.openrewrite.java.Assertions.java;
25 |
26 | class LoggingExceptionConcatenationTest implements RewriteTest {
27 |
28 | @Override
29 | public void defaults(RecipeSpec spec) {
30 | spec.recipe(new LoggingExceptionConcatenationRecipe())
31 | .parser(JavaParser.fromJavaVersion().classpath("log4j-api"));
32 | }
33 |
34 | @DocumentExample
35 | @Test
36 | void loggingException() {
37 | rewriteRun(
38 | //language=java
39 | java(
40 | """
41 | import org.apache.logging.log4j.Logger;
42 |
43 | class Test {
44 | void test(Logger logger, RuntimeException e) {
45 | logger.error("test" + e);
46 | }
47 | }
48 | """,
49 | """
50 | import org.apache.logging.log4j.Logger;
51 |
52 | class Test {
53 | void test(Logger logger, RuntimeException e) {
54 | logger.error("test", e);
55 | }
56 | }
57 | """
58 | )
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/log4j/PrependRandomNameTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.log4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 |
25 | import static org.openrewrite.java.Assertions.java;
26 |
27 | class PrependRandomNameTest implements RewriteTest {
28 |
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipe(new PrependRandomName(2048))
32 | .parser(JavaParser.fromJavaVersion()
33 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-1.2.+"));
34 | }
35 |
36 | @DocumentExample
37 | @Test
38 | void prependRandomName() {
39 | //language=java
40 | rewriteRun(
41 | java(
42 | """
43 | import org.apache.log4j.Logger;
44 |
45 | class Test {
46 | Logger logger;
47 | void test() {
48 | logger.info("test");
49 | }
50 | }
51 | """,
52 | """
53 | import org.apache.log4j.Logger;
54 |
55 | class Test {
56 | Logger logger;
57 | void test() {
58 | logger.info("
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.test.RewriteTest;
21 |
22 | import static org.openrewrite.xml.Assertions.xml;
23 |
24 | class ConfigureLoggerLevelTest implements RewriteTest {
25 |
26 | @DocumentExample
27 | @Test
28 | void editExistingLogger() {
29 | rewriteRun(
30 | spec -> spec.recipe(new ConfigureLoggerLevel("org.springframework", ConfigureLoggerLevel.LogLevel.off)),
31 | xml(//language=xml
32 | """
33 |
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 |
25 | import static org.openrewrite.java.Assertions.java;
26 |
27 | class Log4jAppenderToLogbackTest implements RewriteTest {
28 |
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipe(new Log4jAppenderToLogback())
32 | .parser(JavaParser.fromJavaVersion()
33 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-1.2.+"));
34 | }
35 |
36 | @DocumentExample
37 | @Test
38 | void appenderMigration() {
39 | //language=java
40 | rewriteRun(
41 | java(
42 | """
43 | import org.apache.log4j.AppenderSkeleton;
44 | import org.apache.log4j.spi.LoggingEvent;
45 |
46 | class TrivialAppender extends AppenderSkeleton {
47 | @Override
48 | protected void append(LoggingEvent event) {
49 | String s = this.layout.format(event);
50 | System.out.println(s);
51 | }
52 |
53 | @Override
54 | public void close() {
55 | // nothing to do
56 | }
57 |
58 | @Override
59 | public boolean requiresLayout() {
60 | return true;
61 | }
62 | }
63 | """,
64 | """
65 | import ch.qos.logback.classic.spi.ILoggingEvent;
66 | import ch.qos.logback.core.AppenderBase;
67 |
68 | class TrivialAppender extends AppenderBase
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.logback;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 |
25 | import static org.openrewrite.java.Assertions.java;
26 |
27 | class Log4jLayoutToLogbackTest implements RewriteTest {
28 |
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipe(new Log4jLayoutToLogback())
32 | .parser(JavaParser.fromJavaVersion()
33 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-1.2.+"));
34 | }
35 |
36 | @DocumentExample
37 | @Test
38 | void layoutMigration() {
39 | //language=java
40 | rewriteRun(
41 | java(
42 | """
43 | import org.apache.log4j.Layout;
44 | import org.apache.log4j.spi.LoggingEvent;
45 |
46 | class TrivialLayout extends Layout {
47 |
48 | @Override
49 | public void activateOptions() {
50 | // there are no options to activate
51 | }
52 |
53 | @Override
54 | public String format(LoggingEvent event) {
55 | return event.getRenderedMessage();
56 | }
57 |
58 | @Override
59 | public boolean ignoresThrowable() {
60 | return true;
61 | }
62 | }
63 | """,
64 | """
65 | import ch.qos.logback.classic.spi.ILoggingEvent;
66 | import ch.qos.logback.core.LayoutBase;
67 |
68 | class TrivialLayout extends LayoutBase
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.java.JavaParser;
22 | import org.openrewrite.test.RecipeSpec;
23 | import org.openrewrite.test.RewriteTest;
24 |
25 | import static org.openrewrite.java.Assertions.java;
26 |
27 | class ChangeLogLevelTest implements RewriteTest {
28 |
29 | @Override
30 | public void defaults(RecipeSpec spec) {
31 | spec.recipe(new ChangeLogLevel(ChangeLogLevel.Level.INFO, ChangeLogLevel.Level.DEBUG, "LaunchDarkly"))
32 | .parser(JavaParser.fromJavaVersion()
33 | .classpathFromResources(new InMemoryExecutionContext(), "slf4j-api-2.1.+"));
34 | }
35 |
36 | @DocumentExample
37 | @Test
38 | void basic() {
39 | rewriteRun(
40 | //language=java
41 | java(
42 | """
43 | import org.slf4j.Logger;
44 | import org.slf4j.LoggerFactory;
45 |
46 | class Test {
47 | private static final Logger log = LoggerFactory.getLogger(Test.class);
48 |
49 | void test() {
50 | log.info("LaunchDarkly Hello");
51 | }
52 | }
53 | """,
54 | """
55 | import org.slf4j.Logger;
56 | import org.slf4j.LoggerFactory;
57 |
58 | class Test {
59 | private static final Logger log = LoggerFactory.getLogger(Test.class);
60 |
61 | void test() {
62 | log.debug("LaunchDarkly Hello");
63 | }
64 | }
65 | """
66 | )
67 | );
68 | }
69 |
70 | @Test
71 | void concatenatedString() {
72 | rewriteRun(
73 | //language=java
74 | java(
75 | """
76 | import org.slf4j.Logger;
77 | import org.slf4j.LoggerFactory;
78 |
79 | class Test {
80 | private static final Logger log = LoggerFactory.getLogger(Test.class);
81 |
82 | void test() {
83 | log.info("LaunchDarkly " + 1 + "Hello");
84 | }
85 | }
86 | """,
87 | """
88 | import org.slf4j.Logger;
89 | import org.slf4j.LoggerFactory;
90 |
91 | class Test {
92 | private static final Logger log = LoggerFactory.getLogger(Test.class);
93 |
94 | void test() {
95 | log.debug("LaunchDarkly " + 1 + "Hello");
96 | }
97 | }
98 | """
99 | )
100 | );
101 | }
102 |
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/slf4j/CommonsLoggingToSlf4j1Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.config.Environment;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 | import org.openrewrite.test.TypeValidation;
26 |
27 | import static org.openrewrite.java.Assertions.java;
28 |
29 | class CommonsLoggingToSlf4j1Test implements RewriteTest {
30 |
31 | @Override
32 | public void defaults(RecipeSpec spec) {
33 | spec.typeValidationOptions(TypeValidation.builder().build())
34 | .recipe(Environment.builder()
35 | .scanRuntimeClasspath("org.openrewrite.java.logging")
36 | .build()
37 | .activateRecipes("org.openrewrite.java.logging.slf4j.CommonsLogging1ToSlf4j1"))
38 | .parser(JavaParser.fromJavaVersion()
39 | .classpathFromResources(new InMemoryExecutionContext(), "commons-logging-1.3.+", "slf4j-api-2.1.+", "lombok-1.18.+"));
40 | }
41 |
42 | @DocumentExample
43 | @Test
44 | void useLoggerFactory() {
45 | //language=java
46 | rewriteRun(
47 | java(
48 | """
49 | import org.apache.commons.logging.LogFactory;
50 | import org.apache.commons.logging.Log;
51 |
52 | class Test {
53 | Log logger0 = LogFactory.getLog(Test.class);
54 | Log logger1 = LogFactory.getLog("foobar");
55 | Log logger2 = LogFactory.getFactory().getInstance(Test.class);
56 | Log logger3 = LogFactory.getFactory().getInstance("foobar");
57 | }
58 | """,
59 | """
60 | import org.slf4j.Logger;
61 | import org.slf4j.LoggerFactory;
62 |
63 | class Test {
64 | Logger logger0 = LoggerFactory.getLogger(Test.class);
65 | Logger logger1 = LoggerFactory.getLogger("foobar");
66 | Logger logger2 = LoggerFactory.getLogger(Test.class);
67 | Logger logger3 = LoggerFactory.getLogger("foobar");
68 | }
69 | """
70 | )
71 | );
72 | }
73 |
74 | @Test
75 | void staticFinalLoggerIsStaticFinal() {
76 | //language=java
77 | rewriteRun(
78 | java(
79 | """
80 | import org.apache.commons.logging.LogFactory;
81 | import org.apache.commons.logging.Log;
82 |
83 | class Test {
84 | private static final Log logger0 = LogFactory.getLog(Test.class);
85 | private static final Log logger1 = LogFactory.getLog("foobar");
86 | private static final Log logger2 = LogFactory.getFactory().getInstance(Test.class);
87 | private static final Log logger3 = LogFactory.getFactory().getInstance("foobar");
88 | }
89 | """,
90 | """
91 | import org.slf4j.Logger;
92 | import org.slf4j.LoggerFactory;
93 |
94 | class Test {
95 | private static final Logger logger0 = LoggerFactory.getLogger(Test.class);
96 | private static final Logger logger1 = LoggerFactory.getLogger("foobar");
97 | private static final Logger logger2 = LoggerFactory.getLogger(Test.class);
98 | private static final Logger logger3 = LoggerFactory.getLogger("foobar");
99 | }
100 | """
101 | )
102 | );
103 | }
104 |
105 | @Test
106 | void logLevelFatalToError() {
107 | //language=java
108 | rewriteRun(
109 | java(
110 | """
111 | import org.apache.commons.logging.Log;
112 |
113 | class Test {
114 | static void method(Log logger) {
115 | if (logger.isFatalEnabled()) {
116 | logger.fatal("uh oh");
117 | }
118 | }
119 | }
120 | """,
121 | """
122 | import org.slf4j.Logger;
123 |
124 | class Test {
125 | static void method(Logger logger) {
126 | if (logger.isErrorEnabled()) {
127 | logger.error("uh oh");
128 | }
129 | }
130 | }
131 | """
132 | )
133 | );
134 | }
135 |
136 | @Test
137 | void changeLombokLogAnnotation() {
138 | //language=java
139 | rewriteRun(
140 | spec -> spec.typeValidationOptions(TypeValidation.builder().identifiers(false).methodInvocations(false).build()),
141 | java(
142 | """
143 | import lombok.extern.apachecommons.CommonsLog;
144 |
145 | @CommonsLog
146 | class Test {
147 | void method() {
148 | log.info("uh oh");
149 | }
150 | }
151 | """,
152 | """
153 | import lombok.extern.slf4j.Slf4j;
154 |
155 | @Slf4j
156 | class Test {
157 | void method() {
158 | log.info("uh oh");
159 | }
160 | }
161 | """
162 | )
163 | );
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/slf4j/Log4j1ToSlf4j1Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.Issue;
22 | import org.openrewrite.config.Environment;
23 | import org.openrewrite.java.JavaParser;
24 | import org.openrewrite.test.RecipeSpec;
25 | import org.openrewrite.test.RewriteTest;
26 |
27 | import static org.openrewrite.java.Assertions.java;
28 |
29 | class Log4j1ToSlf4j1Test implements RewriteTest {
30 |
31 | @Override
32 | public void defaults(RecipeSpec spec) {
33 | spec.recipe(Environment.builder()
34 | .scanRuntimeClasspath("org.openrewrite.java.logging")
35 | .build()
36 | .activateRecipes("org.openrewrite.java.logging.slf4j.Log4j1ToSlf4j1"))
37 | .parser(JavaParser.fromJavaVersion()
38 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-1.2.+"));
39 | }
40 |
41 | @DocumentExample
42 | @Test
43 | void useLoggerFactory() {
44 | //language=java
45 | rewriteRun(
46 | java(
47 | """
48 | import org.apache.log4j.Logger;
49 |
50 | class Test {
51 | Logger logger0 = Logger.getLogger(Test.class);
52 | }
53 | """,
54 | """
55 | import org.slf4j.Logger;
56 | import org.slf4j.LoggerFactory;
57 |
58 | class Test {
59 | Logger logger0 = LoggerFactory.getLogger(Test.class);
60 | }
61 | """
62 | )
63 | );
64 | }
65 |
66 | @Test
67 | void staticFinalLoggerIsStaticFinal() {
68 | //language=java
69 | rewriteRun(
70 | java(
71 | """
72 | import org.apache.log4j.Logger;
73 |
74 | class A {
75 | private static final Logger logger = Logger.getLogger(A.class);
76 | }
77 | """,
78 | """
79 | import org.slf4j.Logger;
80 | import org.slf4j.LoggerFactory;
81 |
82 | class A {
83 | private static final Logger logger = LoggerFactory.getLogger(A.class);
84 | }
85 | """
86 | ),
87 | java(
88 | """
89 | import org.apache.log4j.Logger;
90 | import org.apache.log4j.LogManager;
91 |
92 | class B {
93 | private static final Logger logger = LogManager.getLogger(B.class);
94 | }
95 | """,
96 | """
97 | import org.slf4j.Logger;
98 | import org.slf4j.LoggerFactory;
99 |
100 | class B {
101 | private static final Logger logger = LoggerFactory.getLogger(B.class);
102 | }
103 | """
104 | ),
105 | java(
106 | """
107 | import org.apache.log4j.Logger;
108 | import org.apache.log4j.LogManager;
109 |
110 | class C {
111 | private static final Logger logger = LogManager.getLogger("C");
112 | }
113 | """,
114 | """
115 | import org.slf4j.Logger;
116 | import org.slf4j.LoggerFactory;
117 |
118 | class C {
119 | private static final Logger logger = LoggerFactory.getLogger("C");
120 | }
121 | """
122 | )
123 | );
124 | }
125 |
126 | @Test
127 | void logLevelFatalToError() {
128 | //language=java
129 | rewriteRun(
130 | java(
131 | """
132 | import org.apache.log4j.Logger;
133 |
134 | class Test {
135 | static void method(Logger logger) {
136 | logger.fatal("uh oh");
137 | }
138 | }
139 | """,
140 | """
141 | import org.slf4j.Logger;
142 |
143 | class Test {
144 | static void method(Logger logger) {
145 | logger.error("uh oh");
146 | }
147 | }
148 | """
149 | )
150 | );
151 | }
152 |
153 | @Test
154 | @Issue("https://github.com/openrewrite/rewrite-logging-frameworks/issues/47")
155 | void migrateMDC() {
156 | //language=java
157 | rewriteRun(
158 | java(
159 | """
160 | import org.apache.log4j.MDC;
161 |
162 | class Test {
163 | static void method() {
164 | MDC.clear();
165 | }
166 | }
167 | """,
168 | """
169 | import org.slf4j.MDC;
170 |
171 | class Test {
172 | static void method() {
173 | MDC.clear();
174 | }
175 | }
176 | """
177 | )
178 | );
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/slf4j/Log4j2ToSlf4j1Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.config.Environment;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 | import org.openrewrite.test.TypeValidation;
26 |
27 | import static org.openrewrite.java.Assertions.java;
28 |
29 | class Log4j2ToSlf4j1Test implements RewriteTest {
30 | @Override
31 | public void defaults(RecipeSpec spec) {
32 | spec.recipe(Environment.builder()
33 | .scanRuntimeClasspath("org.openrewrite.java.logging")
34 | .build()
35 | .activateRecipes("org.openrewrite.java.logging.slf4j.Log4j2ToSlf4j1"))
36 | .parser(JavaParser.fromJavaVersion()
37 | .classpathFromResources(new InMemoryExecutionContext(), "log4j-api-2.+", "log4j-core-2.+", "lombok-1.18.+"));
38 | }
39 |
40 | @DocumentExample
41 | @Test
42 | void logLevelFatalToError() {
43 | //language=java
44 | rewriteRun(
45 | java(
46 | """
47 | import org.apache.logging.log4j.Logger;
48 |
49 | class Test {
50 | static void method(Logger logger) {
51 | logger.fatal("uh oh");
52 | }
53 | }
54 | """,
55 | """
56 | import org.slf4j.Logger;
57 |
58 | class Test {
59 | static void method(Logger logger) {
60 | logger.error("uh oh");
61 | }
62 | }
63 | """
64 | )
65 | );
66 | }
67 |
68 | @Test
69 | void loggerUsage() {
70 | //language=java
71 | rewriteRun(
72 | java(
73 | """
74 | import org.apache.logging.log4j.Logger;
75 | import org.apache.logging.log4j.LogManager;
76 |
77 | class Test {
78 | private static final Logger LOGGER = LogManager.getLogger(Test.class);
79 | private static final Logger ROOT_LOGGER = LogManager.getRootLogger();
80 |
81 | public static void main(String[] args) {
82 | if (LOGGER.isDebugEnabled()) {
83 | LOGGER.debug("logger message");
84 | }
85 | ROOT_LOGGER.info("root logger message");
86 | }
87 | }
88 | """,
89 | """
90 | import org.slf4j.Logger;
91 | import org.slf4j.LoggerFactory;
92 |
93 | class Test {
94 | private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
95 | private static final Logger ROOT_LOGGER = LoggerFactory.getRootLogger();
96 |
97 | public static void main(String[] args) {
98 | if (LOGGER.isDebugEnabled()) {
99 | LOGGER.debug("logger message");
100 | }
101 | ROOT_LOGGER.info("root logger message");
102 | }
103 | }
104 | """
105 | )
106 | );
107 | }
108 |
109 | @Test
110 | void changeLombokLogAnnotation() {
111 | //language=java
112 | rewriteRun(
113 | spec -> spec.typeValidationOptions(TypeValidation.builder().identifiers(false).methodInvocations(false).build()),
114 | java(
115 | """
116 | import lombok.extern.log4j.Log4j;
117 |
118 | @Log4j
119 | class Test {
120 | void method() {
121 | log.info("uh oh");
122 | }
123 | }
124 | """,
125 | """
126 | import lombok.extern.slf4j.Slf4j;
127 |
128 | @Slf4j
129 | class Test {
130 | void method() {
131 | log.info("uh oh");
132 | }
133 | }
134 | """
135 | )
136 | );
137 | }
138 |
139 | @Test
140 | void unparameterizedLogging() {
141 | //language=java
142 | rewriteRun(
143 | java(
144 | """
145 | package foo;
146 | public class LogConstants {
147 | public static final String CONSTANT = "constant";
148 | }
149 | """
150 | ),
151 | java(
152 | """
153 | import foo.LogConstants;
154 | import org.apache.logging.log4j.Logger;
155 |
156 | class Test {
157 | Logger logger;
158 | void method(String arg) {
159 | logger.info(LogConstants.CONSTANT + arg);
160 | }
161 | }
162 | """,
163 | """
164 | import foo.LogConstants;
165 | import org.slf4j.Logger;
166 |
167 | class Test {
168 | Logger logger;
169 | void method(String arg) {
170 | logger.info("{}{}", LogConstants.CONSTANT, arg);
171 | }
172 | }
173 | """
174 | )
175 | );
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/src/test/java/org/openrewrite/java/logging/slf4j/Slf4jBestPracticesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 the original author or authors.
3 | *
4 | * Licensed under the Moderne Source Available License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://docs.moderne.io/licensing/moderne-source-available-license
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.openrewrite.java.logging.slf4j;
17 |
18 | import org.junit.jupiter.api.Test;
19 | import org.openrewrite.DocumentExample;
20 | import org.openrewrite.InMemoryExecutionContext;
21 | import org.openrewrite.config.Environment;
22 | import org.openrewrite.java.JavaParser;
23 | import org.openrewrite.test.RecipeSpec;
24 | import org.openrewrite.test.RewriteTest;
25 |
26 | import static org.openrewrite.java.Assertions.java;
27 |
28 | class Slf4jBestPracticesTest implements RewriteTest {
29 |
30 | @Override
31 | public void defaults(RecipeSpec spec) {
32 | spec.recipe(Environment.builder()
33 | .scanRuntimeClasspath("org.openrewrite.java.logging.slf4j")
34 | .build()
35 | .activateRecipes("org.openrewrite.java.logging.slf4j.Slf4jBestPractices"))
36 | .parser(JavaParser.fromJavaVersion()
37 | .classpathFromResources(new InMemoryExecutionContext(), "slf4j-api-2.1.+"));
38 | }
39 |
40 | @DocumentExample
41 | @Test
42 | void applyBestPractices() {
43 | //language=java
44 | rewriteRun(
45 | java(
46 | """
47 | import org.slf4j.Logger;
48 | import org.slf4j.LoggerFactory;
49 | class Test {
50 | Logger logger = LoggerFactory.getLogger(String.class);
51 | void test() {
52 | Object obj1 = new Object();
53 | Object obj2 = new Object();
54 | logger.info("Hello " + obj1 + ", " + obj2);
55 | Exception e = new Exception();
56 | logger.warn(String.valueOf(e));
57 | logger.error(e.getMessage());
58 | logger.error(e.getLocalizedMessage());
59 | }
60 | }
61 | """,
62 | """
63 | import org.slf4j.Logger;
64 | import org.slf4j.LoggerFactory;
65 | class Test {
66 | private Logger logger = LoggerFactory.getLogger(Test.class);
67 | void test() {
68 | Object obj1 = new Object();
69 | Object obj2 = new Object();
70 | logger.info("Hello {}, {}", obj1, obj2);
71 | Exception e = new Exception();
72 | logger.warn("Exception", e);
73 | logger.error("", e);
74 | logger.error("", e);
75 | }
76 | }
77 | """
78 | )
79 | );
80 | }
81 |
82 | @SuppressWarnings({"UnnecessaryCallToStringValueOf", "UnnecessaryToStringCall"})
83 | @Test
84 | void exceptionIsAppendedAtEndOfLogMessage() {
85 | //language=java
86 | rewriteRun(
87 | java(
88 | """
89 | import org.slf4j.Logger;
90 | import org.slf4j.LoggerFactory;
91 | class Test {
92 | Logger logger = LoggerFactory.getLogger(Test.class);
93 | void test() {
94 | try {
95 | throw new IllegalStateException("oops");
96 | } catch (Exception e) {
97 | logger.error("aaa: " + e);
98 | logger.error("bbb: " + String.valueOf(e));
99 | logger.error("ccc: " + e.toString());
100 | }
101 | }
102 | }
103 | """,
104 | """
105 | import org.slf4j.Logger;
106 | import org.slf4j.LoggerFactory;
107 | class Test {
108 | private Logger logger = LoggerFactory.getLogger(Test.class);
109 | void test() {
110 | try {
111 | throw new IllegalStateException("oops");
112 | } catch (Exception e) {
113 | logger.error("aaa: {}", e);
114 | logger.error("bbb: {}", String.valueOf(e));
115 | logger.error("ccc: {}", e.toString());
116 | }
117 | }
118 | }
119 | """
120 | )
121 | );
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/suppressions.xml:
--------------------------------------------------------------------------------
1 |
2 |