GithubHelp home page GithubHelp logo

slf4j-test's Introduction

slf4j-test's People

Contributors

mahoney avatar philipa avatar stephan202 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slf4j-test's Issues

Add a LICENSE to project

Hi there, I recently found this library and think it would be very useful for testing some projects I'm working on. Unfortunately I haven't seen a license listed anywhere in the repo or on the project website. Would you consider adding an open source license?

LoggingEvent#getFormattedMessage() doesn't format nulls the same way as SLF4J

Although LoggingEvent#getFormattedMessage() isn't public (#28), its code is still usable as a reference. However, it doesn't present null values the same way as SLF4J, due to un-matched wrapping/unwrapping of Optional:

        LoggingEvent e = new LoggingEvent(Level.INFO, "Content: {}, {}", null, "value");
        System.out.println(MessageFormatter.arrayFormat(e.getMessage(), e.getArguments().toArray()).getMessage());

Produces:

Content: Optional.absent(), value

Rather than the expected:

Content: null, value

JDK6 compatibility request

It looks like I'm only able to use this in Java 7; is there any way you can modify it to work with Java 6 as well (or accept patches)? I know Java6 is now EOL, but (at least where I work) there is a substantial amount of older code around that won't be validated with Java 7 anytime too soon.

Sbt dependency instructions are wrong

I'd just give you a pull request, but I don't quite understand how the dependency page is being generated. It might be something done automatically for you, in which case, this can just remain as documentation.

The dependency page provides SBT instructions that would be appropriate for a scala library, but this being a java library, it makes sbt look for a dependency that doesn't exist.

the double percentage (%%) it suggests will try to append your version of scala to the dependency resolver, as Scala bytecode is not compatible between major versions. A java library should use a single percentage instead, and then the library will be found just fine.

TestLogger is not serializable

The SLF4J FAQ states:

As of SLF4J version 1.5.3, logger instances survive serialization. Thus, serialization of the host class no longer requires any special action, even when loggers are declared as instance variables.

This is true of the official bindings, but not slf4j-test.

Test case (can be added to TestLoggerTests.java):

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

public class TestLoggerTests {
    // ...

    @Test
    public void serializable() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        new ObjectOutputStream(outStream).writeObject(testLogger);
        ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
        TestLogger deserializedLogger = (TestLogger) new ObjectInputStream(inStream).readObject();
        deserializedLogger.info(message);

        assertEquals(asList(info(mdcValues, message)), deserializedLogger.getLoggingEvents());
    }

}

Test output:

serializable(uk.org.lidalia.slf4jtest.TestLoggerTests)  Time elapsed: 0.095 sec  <<< ERROR!
java.io.NotSerializableException: uk.org.lidalia.slf4jtest.TestLogger
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at uk.org.lidalia.slf4jtest.TestLoggerTests.serializable(TestLoggerTests.java:313)

Current workarounds include:

  • Use static loggers instead of per-instance loggers
  • In Scala, instance loggers can be marked lazy transient

(By the way, thanks for the great library!)

Doesn't seem to be possible to test with Spring Boot and logstash-logback-encoder

Raising here, similar to the issue I've raised at logfellow/logstash-logback-encoder#526.

When using the sample project at https://gitlab.com/jamietanna/logstash-boot-slf4j-test/-/tree/main/complete, we see the following exception:

ch/qos/logback/classic/joran/JoranConfigurator
java.lang.NoClassDefFoundError: ch/qos/logback/classic/joran/JoranConfigurator
	at org.springframework.boot.logging.logback.LogbackLoggingSystem$Factory.getLoggingSystem(LogbackLoggingSystem.java:352)
	at org.springframework.boot.logging.DelegatingLoggingSystemFactory.getLoggingSystem(DelegatingLoggingSystemFactory.java:44)
	at org.springframework.boot.logging.LoggingSystem.get(LoggingSystem.java:159)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:231)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:213)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
	at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:76)
	at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:53)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
	at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:53)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:317)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:350)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:355)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$7(ClassBasedTestDescriptor.java:350)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:349)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$4(ClassBasedTestDescriptor.java:270)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:269)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
	at java.base/java.util.Optional.orElseGet(Optional.java:369)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
	at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.ClassNotFoundException: ch.qos.logback.classic.joran.JoranConfigurator
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)

Similar to #21.

I wonder if this is something to fix upstream in Spring, where Spring should look for a class in logback-classic, not a class in logback-core

classpathDependencyExcludes are not picked up by IntelliJ

The solution as described in the documentation, with surefire classpathDependencyExcludes, does not work when run through IntelliJ.
This causes this logging framework to work correctly on commandline, but still cause logging framework conflicts when run in IntelliJ.

Is there a way to make this framework compatible with IntelliJ?

Spring context and TestLogger introduce binding exception

Hi,
We have a spring boot application, set up using Gradle.
The test for the logger works.
We added another test, not for the logger, using SpringRunner:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)

This test fail due to problem with multiple binding of classes.
I tried many options to exclude different libraries from the gradle build, but no success.

Here's our dependencies in the build.gradle file:
(without exclusions. the "original" build file)

  compile(
    'com.google.code.gson:gson:2.8.5',
    'com.squareup.okhttp3:okhttp:3.11.0',
    'commons-io:commons-io:2.6',
    'com.datadoghq:java-dogstatsd-client:2.4',
    'commons-io:commons-io:2.6',
    'net.logstash.logback:logstash-logback-encoder:5.+',
    'org.projectlombok:lombok:1.18.4',
    'org.springframework.boot:spring-boot-configuration-processor',
    'org.springframework.boot:spring-boot-starter-actuator',
    'org.springframework.boot:spring-boot-starter-data-cassandra',
    'org.springframework.boot:spring-boot-starter-integration',
    'org.springframework.boot:spring-boot-starter-web',
  )

  testCompile 'uk.org.lidalia:slf4j-test:1.1.0'
  testCompile 'org.springframework.boot:spring-boot-starter-test'
  testCompile 'com.google.guava:guava:27.0-jre'
  testCompile 'org.springframework.boot:spring-boot-starter-test'

Here's the exception we get:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/eyalgo/.gradle/caches/modules-2/files-2.1/uk.org.lidalia/slf4j-test/1.1.0/f4f523049e041dea673bd421d7b0d61fb5e49548/slf4j-test-1.1.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/eyalgo/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.3/7c4f3c474fb2c041d8028740440937705ebb473a/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [uk.org.lidalia.slf4jtest.TestLoggerFactory]

java.lang.IllegalStateException: Failed to load ApplicationContext

	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class uk.org.lidalia.slf4jtest.TestLoggerFactory loaded from file:/Users/eyalgo/.gradle/caches/modules-2/files-2.1/uk.org.lidalia/slf4j-test/1.1.0/f4f523049e041dea673bd421d7b0d61fb5e49548/slf4j-test-1.1.0.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: uk.org.lidalia.slf4jtest.TestLoggerFactory
	at org.springframework.util.Assert.instanceCheckFailed(Assert.java:655)
	at org.springframework.util.Assert.isInstanceOf(Assert.java:555)
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:286)
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:102)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:217)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:196)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
	at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:69)
	at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:48)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
	... 24 more

Compatibility with SLF4J 2.0

First of all, thank you for maintaining this very useful utility!

Unfortunately, starting with SLF4J 2.0, it doesn't work anymore. SLF4J 2.0 changed the way it discovers implementations. Quoting from their documentation:

Instead of "bindings" now org.slf4j.LoggerFactory searches for "providers".

Although I'm not an expert on SLF4J, I managed to implement such a provider. If you're open to such a contribution, I can create a PR for it.

This example doesn't work

public class Slf4jUser {

private static final Logger logger = LoggerFactory.getLogger(Slf4jUser.class);

public void aMethodThatLogs() {
    logger.info("Hello World!");
}

}

public class Slf4jUserTest {

Slf4jUser slf4jUser = new Slf4jUser();
TestLogger logger = TestLoggerFactory.getTestLogger(Slf4jUser.class);

@Test
public void aMethodThatLogsLogsAsExpected() {
    slf4jUser.aMethodThatLogs();

    assertThat(logger.getLoggingEvents(), is(asList(info("Hello World!"))));
}

@After
public void clearLoggers() {
    TestLoggerFactory.clear();
}

}

This test case throws
java.lang.AssertionError:
Expected: is <[LoggingEvent[level=INFO,mdc={},marker=Optional.absent(),throwable=Optional.absent(),message=Hello World!,arguments=[]]]>
but: was <[]>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
at dozerExp.Slf4jUserTest.aMethodThatLogsLogsAsExpected(Slf4jUserTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

equals implementation broken in 1.1.0

These look equal to me, here's my source (obviously the commented out line is not when I run it)

https://bitbucket.org/xenworks/logging/src/d5037e058b95bed7b5114f55ce18ccc85c954551/src/test/java/com/xenoterracide/logging/LoggableTest.java?at=master&fileviewer=file-view-default#LoggableTest.java-49

Expected :uk.org.lidalia.slf4jtest.LoggingEvent<LoggingEvent[level=TRACE,mdc={},marker=Optional.absent(),throwable=Optional.absent(),message=test {},arguments=[1]]> 
Actual   :uk.org.lidalia.slf4jtest.LoggingEvent<LoggingEvent[level=TRACE,mdc={},marker=Optional.absent(),throwable=Optional.absent(),message=test {},arguments=[1]]>

I did a little investigation, this is where it fails

&& fieldsOfThis.allMatch(hasEqualValueIn(that));

LoggingEvent should accept a null message

Other Slf4j implementations accept a null for the message when logging. I believe the slf4j API also doesn't label the message as @nonnull.

Currently LoggingEvent has a checkNotNull check on message. Which causes my existing code, that does log a null, to get an NPE. I think it was probably done to be like the checks on the other Optional fields.

Make LoggingEvent::getFormattedMessage public

In tests, I want to make assertions on the message that is generated in the logging system, not the template with positional args with "{}".

It could therefore be hard to test arguments, as it should need creating real instance of objects passed as args to logging, not just text really logged

Support slf4j api 2.0

in slf2.0
it uses LoggerFactory.findServiceProviders(...) to load slf implement module
which needs to implement
org.slf4j.spi.SLF4JServiceProvider interface.
we could fix it by add TestLogbackServiceProvider.java and add service definition file in
META-INF/services/org.slf4j.spi.SLF4JServiceProvider

like

	private MDCAdapter mdcAdapter;
	private ILoggerFactory loggerFactory;
	private IMarkerFactory markerFactory;
	@Override
	public ILoggerFactory getLoggerFactory() {
		return loggerFactory;
	}

	@Override
	public IMarkerFactory getMarkerFactory() {
		return markerFactory;
	}

	@Override
	public MDCAdapter getMDCAdapter() {
		return mdcAdapter;
	}

	@Override
	public String getRequestedApiVersion() {
		return "2.0.1";
	}

	@Override
	public void initialize() {
		mdcAdapter = StaticMDCBinder.SINGLETON.getMDCA();
		loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory();
		markerFactory = StaticMarkerBinder.SINGLETON.getMarkerFactory();
	}
}`

and 
META-INF/services/org.slf4j.spi.SLF4JServiceProvider
content is 
$packagename.TestLogbackServiceProvider

Enhancment - Hamcrest matchers

I'm finding the following useful:

public static Matcher<LoggingEvent> debugContaining(String substring) {
    return formattedMessageMatches(Level.DEBUG, substring);
}

/// etc.

private static Matcher<LoggingEvent> formattedMessageMatches(
    final Level debug, final String substring) {

    return new BaseMatcher<LoggingEvent>() {

        @Override
        public boolean matches(Object item) {

            if (item instanceof LoggingEvent) {
                final LoggingEvent le = (LoggingEvent)item;

                return le.getLevel().equals(debug) &&
                    getFormattedMessage(le).indexOf(substring) >= 0;
            }

            return false;
        }

        @Override
        public void describeTo(Description description) {
            description
                .appendText("LoggingEvent with level ")
                .appendValue(debug)
                .appendText(" and a formatted message containing '")
                .appendText(substring)
                .appendText("'");
        }
    };
}


private static String getFormattedMessage(LoggingEvent event) {
    return MessageFormatter.arrayFormat(
        event.getMessage(), event.getArguments().toArray()).getMessage();
}

So I can say

    assertThat(logger.getAllLoggingEvents(),
        contains(
            debugContaining("first message"),
            debugContaining("the next message")));

Perhaps there should be a LoggingEventMatchers?

SLF4J test Logger function is not working

Hi,

I tried the code based on the sample given. But it was always throwing there is no events in the logger.

I have pasted below the code, log, error for your review. Could you please clarify and help?

Thanks

Raja

package com.charter.aesd.tvgo.app.quartz;

import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.concurrent.Immutable;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

import uk.org.lidalia.slf4jtest.LoggingEvent;
import uk.org.lidalia.slf4jtest.TestLogger;
import uk.org.lidalia.slf4jtest.TestLoggerFactory;

import ch.qos.logback.core.AppenderBase;

import com.charter.aesd.tvgo.transform.conf.LocalS3ClientModule;
import com.charter.aesd.tvgo.transform.conf.LocalTransformationModule;
import com.google.common.collect.ImmutableList;
import com.google.inject.Guice;
import com.google.inject.Injector;
import static uk.org.lidalia.slf4jtest.LoggingEvent.info;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.is;

public class TvGoSchedulerTest {

   /* SLF4J logger with logback */ 
TestLogger logger = TestLoggerFactory.getTestLogger(TvGoFeedSchedulerListener.class);


   @Test
   public void  schedulerTest() throws ParseException, SchedulerException, InterruptedException {
        //schedule it
        Injector injector = Guice.createInjector(new LocalTransformationModule(), new LocalS3ClientModule());
        TvGoFeedJob job = injector.getInstance(TvGoFeedJob.class);

        JobKey jobKeyDummy = new JobKey("jobDummy", "group1");
        JobDetail jobDummy = JobBuilder.newJob(job.getClass())
        .withIdentity(jobKeyDummy).build();


        Trigger triggerDummy = TriggerBuilder
                .newTrigger()
                .withIdentity("triggerDummy", "trgGroup1")
                .withSchedule(
                    CronScheduleBuilder.cronSchedule("0 0/1 * 1/1 * ? *"))
                .build();


        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.getListenerManager().addSchedulerListener(new TvGoFeedSchedulerListener());

        //assertThat(logger.getLoggingEvents(), is(asList(info("Job jobDummy from group group1 is Added to scheduler"))));
        scheduler.start();
        assertThat(logger.getLoggingEvents(), is(asList(info("Scheduler is Started"))));
        scheduler.pauseJob(jobKeyDummy);
        scheduler.resumeJob(jobKeyDummy);
        scheduler.addJob(jobDummy,true);
        scheduler.pauseTrigger(triggerDummy.getKey());
        scheduler.resumeTrigger(triggerDummy.getKey());
        GroupMatcher<JobKey> group = GroupMatcher.groupContains("group");
        scheduler.pauseJobs(group);
        scheduler.resumeJobs(group);
        scheduler.clear();
        scheduler.deleteJob(jobDummy.getKey());
        scheduler.standby();
        scheduler.scheduleJob(jobDummy, triggerDummy);


        scheduler.shutdown();
    }

   @After
   public void clearLog(){
       TestLoggerFactory.clear();

   }

}


Actual Log

21:18:23.564 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Scheduler is Started
21:18:23.564 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job jobDummy from group group1 is Paused
21:18:23.568 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job jobDummy from group group1 is Resumed
21:18:23.568 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job jobDummy from group group1 is Added to scheduler
21:18:23.568 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Trigger triggerDummy of group trgGroup1 is Paused
21:18:23.568 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Trigger triggerDummy of group trgGroup1 is Resumed
21:18:23.578 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Jobs in Group group1 Paused
21:18:23.578 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Jobs in Group group1 Resumed
21:18:23.578 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Scheduling Data Cleared
21:18:23.578 [main] INFO o.q.c.QuartzScheduler - Scheduler DefaultQuartzScheduler_$NON_CLUSTERED paused.
21:18:23.579 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job Scheduler in StandByMode
21:18:23.585 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job jobDummy from group group1 is Added to scheduler
21:18:23.585 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job jobDummy of group group1 is Scheduled to start at Thu May 01 21:18:23 IST 2014
21:18:23.588 [main] INFO o.q.c.QuartzScheduler - Scheduler DefaultQuartzScheduler
$NON_CLUSTERED shutting down.
21:18:23.588 [main] INFO o.q.c.QuartzScheduler - Scheduler DefaultQuartzScheduler
$NON_CLUSTERED paused.
21:18:23.588 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Job Scheduler in StandByMode
21:18:23.588 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Scheduler is Shutting Down
21:18:23.588 [main] INFO c.c.a.t.a.q.TvGoFeedSchedulerListener - Scheduler ShutDown
21:18:23.588 [main] INFO o.q.c.QuartzScheduler - Scheduler DefaultQuartzScheduler
$_NON_CLUSTERED shutdown complete.


Error Trace

java.lang.AssertionError:
Expected: is <[LoggingEvent[level=INFO,mdc={},marker=Optional.absent(),throwable=Optional.absent(),message=Scheduler is Started,arguments=[]]]>
but: was <[]>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:865)
at org.junit.Assert.assertThat(Assert.java:832)
at com.charter.aesd.tvgo.app.quartz.TvGoSchedulerTest.schedulerTest(TvGoSchedulerTest.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Remove dependencies on third-party libraries

First of all - this is a great little library, thanks for sharing.

It would be useful if the dependencies on other third-party libraries could be removed. For example, I was a little surprised to discover I was now dependent on Guava. The biggest problem here is more likely to be version clashes, hence thinking it may be preferential to remove these dependencies.

LoggingEvent.equals should be more lax comparing the Throwable

Just like it is hard to create a logging event with a specific timestamp to compare against, it is also hard to create a specific throwable to compare against. The problem is that Throwable relies on Object.equals which does a shallow comparison, i.e. requires objects to be the same in order to match. So for example, if the two throwables do not refer to the exact same StackTrace object, the comparison fails.

For example, I get this message from junit:

org.opentest4j.AssertionFailedError: log messages ==> iterable contents differ at index [2], expected: uk.org.lidalia.slf4jtest.LoggingEvent@6aa61224<LoggingEvent[level=ERROR,mdc={},marker=Optional.absent(),throwable=Optional.of(java.io.IOException: Broken pipe),message=Failed to write request,arguments=[]]> but was: uk.org.lidalia.slf4jtest.LoggingEvent@30bce90b<LoggingEvent[level=ERROR,mdc={},marker=Optional.absent(),throwable=Optional.of(java.io.IOException: Broken pipe),message=Failed to write request,arguments=[]]>

where the expected value was created by

LoggingEvent.error(new IOException("Broken pipe"),"Failed to write request")

The comparison of the Throwable could for example be changed to require that the just class and message was the same.

Support for SLF4J 2.0

It would be beneficial if we can continue using slf4j test, even when we migrate to SLF4J 2.0.x.

I am aware that this is a major undertaking, and it appears that you no longer actively maintain slf4j-test. I would like to volunteer for that work, either in this project, or I could fork the project to my own user and continue the work from there. In any case, the goal would be to produce a version 2 of slf4j-test that works with SLF4J 2.0.x.

Push slf4j-test to maven central

Hey,
I can't find slf4j-test in the maven central repository. Please push it to sonatype and add the artifact coordinates to the readme.md

null not handled correctly for npe

Null pointer exception is not getting handled correctly, because npe.getMessage() is itself null.

@slf4j
public class Demo {
public static void doIt(){
Map<String, String> map = new ConcurrentHashMap<>();
try {
map.put(null, null);
} catch (NullPointerException npe) {
log.error(npe.getMessage(), npe);
}
}
}

class DemoTest extends Specification {
def "DoIt"() {
given:
TestLogger logger = TestLoggerFactory.getTestLogger(Demo.class);
Demo.doIt();
expect:
logger.getAllLoggingEvents().size() > 0;
}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.