zolyfarkas / spf4j

Simple performance framework for java

Home Page:http://www.spf4j.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dynamic change of log level for given logger?

mikolajmitura opened this issue · comments

Hi,
How to do dynamic change of default log level for given logger?
I tried via TestLoggers.sys().getLogger("loggerName")
But returned TestLogger doesn't have method for change log level.

Thanks in advance :-)

What are you trying to achieve?

If you want to control what is being "printed" and "collected" you can use:

  @Test
  @PrintLogsConfigs( // what logs should be printed.
          {
            @PrintLogs(ideMinLevel = Level.TRACE),
            @PrintLogs(category = "com.sun", ideMinLevel = Level.WARN)
          }
  )
  @CollectLogs(minLevel = Level.TRACE) //what logs should be collected for the log on failure.
  public void testLogging() {

and the API equivalents.

thanks for your response.
I want write tests for my own logging with suppliers as arguments and I have checks for isDebugEnabled and for all those type of methods.
I want to check that if somebody call method which will log debug message when debug is enabled then I expecting that message will be logged, when level is higher than debug for example info, then debug message is not logged and suppliers aren't called...
Earlier I used library:

        <dependency>
            <groupId>uk.org.lidalia</groupId>
            <artifactId>slf4j-test</artifactId>
            <version>1.2.0</version>
            <scope>test</scope>
        </dependency>

which support dynamic change of log level.

TestLogger LOG = TestLoggerFactory.getTestLogger(ClassWithLogger.class);
LOG.setEnabledLevels(Level.INFO);

So I tried to migrate from this above (is quite old) for spf4j-slf4j-test :-)
But I suppose I need to create some loggers and call log message on them directly in test...

There is no need to do that,

keep in mind that the library by default will collect your debug logs silently in a limited buffer, to make them available in case of unit test failure (so isDebug calls will be true). This way you don't have to have verbose builds with gigantic outputs to help you troubleshoot a failure.

what you are trying to do, you can achieve with:

    LogAssert expect = tLog.expect("your.category", Level.DEBUG,
            LogMatchers.hasMatchingFormat(Matchers.equalTo("Booo")));
    
    ... you test code here ...

    expect.assertObservation(); //this will validate that a log message matching the expectation has been made

or collect the logs:

    LogCollection<ArrayDeque<TestLogRecord>> collect = TestLoggers.sys().collect("your.log.category", Level.DEBUG, 10, true);
    LOG.debug("log {}", 1);
    LOG.debug("log {} {}", 1, 2);
    LOG.debug("log {} {} {}", 1, 2, 3);
    LOG.debug("log {} {} {}", 1, 2, 3, 4);
    Assert.assertEquals(4, collect.get().size());

this will allow you to verify the logging behavior during your test.

but when I want that isDebugEnabled return false? How Can I achieve it?

you can disable debug log collections like:

  @Test
  @CollectLogs(minLevel = Level.OFF)
  public void testNoIgnore() {
    Assert.assertFalse(LOG.isDebugEnabled());
  }

but here log level will be changed for LOG instance or in all loggers?
I added @CollectLogs(minLevel = Level.INFO)
and added annotation @RunWith(Spf4jTestLogJUnitRunner.class) for test.
And still anotherLogger.isDebugEnabled() return true
I don't have instance of logger in test, I invoke some method from specific class, and that specific class has own logger, I don't have reference to it...

sorry,
I have tested case like this:

public class LogToolTest {

    private static final Logger LOG = LoggerFactory.getLogger(LogToolTest.class);

    @Test
    @CollectLogs(minLevel = Level.OFF)
    public void testNoIgnore() {
        Assert.assertFalse(LOG.isDebugEnabled());
    }

    @Test
    @CollectLogs(minLevel = Level.DEBUG)
    public void testNoIgnore2() {
        Assert.assertTrue(LOG.isDebugEnabled());
    }

    @Test
    @CollectLogs(minLevel = Level.DEBUG)
    public void testNoIgnore3() {
        ClassWithLogger.expectedLogLevel(true);
    }

    @Test
    @CollectLogs(minLevel = Level.INFO)
    public void testNoIgnore4() {
        ClassWithLogger.expectedLogLevel(false);
    }

    private static class ClassWithLogger
    {
        private static final Logger ANOTHER_LOGGER = LoggerFactory.getLogger(ClassWithLogger.class);

        public static void expectedLogLevel(boolean expected) {
            assertThat(expected).isEqualTo(ANOTHER_LOGGER.isDebugEnabled());
        }
    }
}
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
          
                    <properties>
                        <property>
                            <name>listener</name>
                            <value>org.spf4j.test.log.junit4.Spf4jTestLogRunListener</value> <!-- comma separate multiple listeners -->
                        </property>
                    </properties>
                    <classpathDependencyExcludes>
                        <classpathDependencyExcludes>org.slf4j:slf4j-simple</classpathDependencyExcludes>
                    </classpathDependencyExcludes>
                </configuration>
            </plugin>

and is working fine :-)

but when I added @RunWith(Spf4jTestLogJUnitRunner.class) to class LogToolTest (above one)

@RunWith(Spf4jTestLogJUnitRunner.class)
public class LogToolTest {

with

<properties>
                        <property>
                            <name>listener</name>
                            <value>org.spf4j.test.log.junit4.Spf4jTestLogRunListener</value> <!-- comma separate multiple listeners -->
                        </property>
                    </properties>

it is not working

I got below log

[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ test-project-utils ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 9 source files to C:\repositories\test-project-utils\test-project-utils\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ test-project-utils ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running some.path.LogToolTest
[ERROR] Tests run: 8, Failures: 2, Errors: 4, Skipped: 0, Time elapsed: 0.706 s <<< FAILURE! - in some.path.LogToolTest
[ERROR] Test mechanism  Time elapsed: 0.607 s  <<< ERROR!
java.lang.NullPointerException

[ERROR] Test mechanism  Time elapsed: 0.054 s  <<< ERROR!
java.lang.NullPointerException

[ERROR] testNoIgnore4(some.path.LogToolTest)  Time elapsed: 0.012 s  <<< FAILURE!
org.junit.ComparisonFailure: expected:<[tru]e> but was:<[fals]e>
        at some.path.LogToolTest.testNoIgnore4(LogToolTest.java:40)

[ERROR] Test mechanism  Time elapsed: 0.012 s  <<< ERROR!
java.lang.NullPointerException

[ERROR] testNoIgnore(some.path.LogToolTest)  Time elapsed: 0.001 s  <<< FAILURE!
java.lang.AssertionError
        at some.path.LogToolTest.testNoIgnore(LogToolTest.java:22)

[ERROR] Test mechanism  Time elapsed: 0.002 s  <<< ERROR!
java.lang.NullPointerException

[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR]   LogToolTest.testNoIgnore:22
[ERROR]   LogToolTest.testNoIgnore4:40 expected:<[tru]e> but was:<[fals]e>
[ERROR] Errors:
[ERROR] Test mechanism.Test mechanism
[ERROR]   Run 1: null
[ERROR]   Run 2: null
[ERROR]   Run 3: null
[ERROR]   Run 4: null
[INFO]
[INFO]
[ERROR] Tests run: 5, Failures: 2, Errors: 1, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 38.790 s
[INFO] Finished at: 2019-07-25T13:15:57+02:00
[INFO] Final Memory: 30M/57M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.1:test (default-test) on project test-project-utils: There are test failures.
[ERROR]
[ERROR] Please refer to C:\repositories\test-project-utils\test-project-utils\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] There was an error in the forked process
[ERROR] Test mechanism :: null
[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: There was an error in the forked process
[ERROR] Test mechanism :: null
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:656)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:282)
[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:245)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1183)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:1011)
[ERROR] at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:857)
[ERROR] at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
[ERROR] at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
[ERROR] at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
[ERROR] at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR] at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
[ERROR] at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
[ERROR] at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
[ERROR] at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
[ERROR] at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
[ERROR] at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
[ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
[ERROR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
[ERROR] at java.lang.reflect.Method.invoke(Method.java:508)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

but when I removed properties with listener then build passed correctly...

the 2 listeners interfere with each other, let me see what I can do about it...

@mikolajmitura I have put in a fix to make both work together, and pushed them to maven central: 8.6.18-SNAPSHOT

give it a try and let me know if it works.

thank you

released 8.6.18

8.6.18 resolved this issue, thanks for your help :-)