Skip to content

Commit

Permalink
Merge pull request #15 from dm-drogeriemarkt/keyvalue
Browse files Browse the repository at this point in the history
keyValue matcher, bump versions
  • Loading branch information
cleaning-agent authored Apr 4, 2022
2 parents 625ec2a + 2e2daa7 commit 1f18f62
Show file tree
Hide file tree
Showing 20 changed files with 514 additions and 47 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ jobs:
build:
uses: ./.github/workflows/run-with-maven.yml
with:
COMMAND: mvn --batch-mode -Dmaven.compiler.showDeprecation=true -Dmaven.compiler.showWarnings=true clean verify
COMMAND: >
mvn --batch-mode -Dmaven.compiler.showDeprecation=true -Dmaven.compiler.showWarnings=true -Dproject.version=0.0.0-SNAPSHOT clean install
&& cd project-without-logstash
&& mvn --batch-mode -Dlog-capture.version=0.0.0-SNAPSHOT clean verify
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,26 @@ log.info("did something");
logCapture.info("did something", logger("com.acme.foo"));
```

#### Key-Value (from Logstash)

**Note that** this will only work if logstash-logback-encoder is in your classpath - log-capture does not depend on it, so you need to add it manually if you intend to use it.

```java
import static de.dm.infrastructure.logcapture.ExpectedKeyValue.keyValue;

...

log.info("hello",
StructuredArguments.keyValue("myString", "hello"),
StructuredArguments.keyValue("myNumber", 42)
);

logCapture.assertLogged(info("hello",
keyValue("myString", "hello"),
keyValue("myNumber", 42))
);
```

### Examples

#### Unit Test Example:
Expand Down Expand Up @@ -306,6 +326,12 @@ And with MDC logging context

## Changes

### 3.5.0

* Added new Log Event Matcher: `ExpectedKeyValue.keyValue(...)` to assert `StructuredArguments.keyValue(...)` from Logstash
* Improved readability for assertion errors when using `assertNotLogged(...)`
* Updated dependencies

### 3.4.1

* Improved Javadoc for deprecated methods
Expand Down
41 changes: 30 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@
</developers>

<properties>
<project.version>3.4.1-SNAPSHOT</project.version>
<project.version>3.5.0-SNAPSHOT</project.version>

<java.version>1.8</java.version>
<lombok.version>1.18.20</lombok.version>
<logback.version>1.2.5</logback.version>
<junit.version>5.7.2</junit.version>
<lombok.version>1.18.22</lombok.version>
<logback.version>1.2.11</logback.version>
<logstash-logback-encoder.version>7.0.1</logstash-logback-encoder.version>
<junit.version>5.8.2</junit.version>
<encoding>UTF-8</encoding>

<assertj-core.version>3.20.1</assertj-core.version>
<archunit.version>0.23.1</archunit.version>
<assertj-core.version>3.22.0</assertj-core.version>
<checkstyle.version>8.45.1</checkstyle.version>
<jacoco.version>0.8.7</jacoco.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
Expand All @@ -47,16 +49,11 @@
<maven-compiler-plugin.version>3.9.0</maven-compiler-plugin.version>
<maven-release-plugin.version>2.5.3</maven-release-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<mockito.version>4.4.0</mockito.version>
<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
Expand All @@ -72,12 +69,34 @@
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
</dependency>

<!-- dependencies that are only needed for development of log-capture and are not needed or automatically downloaded when using it -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
<scope>provided</scope>
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>${archunit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
9 changes: 9 additions & 0 deletions project-without-logstash/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/target/

### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
87 changes: 87 additions & 0 deletions project-without-logstash/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>de.acme</groupId>
<artifactId>test-project-without-logstash</artifactId>
<version>0.0.1-SNAPSHOT</version>

<licenses>
<license>
<name>MIT</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>

<properties>
<java.version>1.8</java.version>
<encoding>UTF-8</encoding>
<log-capture.version>3.4.1-SNAPSHOT</log-capture.version>

<lombok.version>1.18.22</lombok.version>
<logback.version>1.2.11</logback.version>
<junit.version>5.8.2</junit.version>
<assertj-core.version>3.22.0</assertj-core.version>

<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.9.0</maven-compiler-plugin.version>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.dm.infrastructure</groupId>
<artifactId>log-capture</artifactId>
<version>${log-capture.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${encoding}</encoding>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.acme;

import de.dm.infrastructure.logcapture.LogCapture;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static de.dm.infrastructure.logcapture.ExpectedKeyValue.keyValue;
import static de.dm.infrastructure.logcapture.LogExpectation.info;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

@Slf4j
public class LogCaptureTest {
@RegisterExtension
LogCapture logCapture = LogCapture.forCurrentPackage();

@Test
void assertionWorksDespiteLogstashNotBeingInTheClasspath() {
log.info("hello");
logCapture.assertLogged(info("hello"));
}

@Test
void errorMessageForKeyValueAssertion() {
log.info("hello");

IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
logCapture.assertLogged(info("hello", keyValue("key", "value"))));

assertThat(thrown).hasMessage("keyValue cannot be used for log assertions if logstash-logback-encoder " +
"that provides StructuredArguments.keyValue(...) is not in the classpath.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public synchronized void doAppend(ILoggingEvent loggingEvent) {
.mdcData(loggingEvent.getMDCPropertyMap())
.loggedException(getLoggedException(loggingEvent.getThrowableProxy()))
.marker(loggingEvent.getMarker())
.argumentArray(loggingEvent.getArgumentArray())
.build());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public String getNonMatchingErrorMessage(LoggedEvent loggedEvent) {
}

@Override
public String getMatchingErrorMessage() {
return format("not expected exception was found: %s", this);
public String getMatcherDetailDescription() {
return format("Exception: %s", this);
}

private static String loggedExceptionToString(Optional<LoggedEvent.LoggedException> optionalException) {
Expand All @@ -70,7 +70,7 @@ private static String loggedExceptionToString(Optional<LoggedEvent.LoggedExcepti
}

@Override
public String getMatcherDescription() {
public String getMatcherTypeDescription() {
return "Exception";
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package de.dm.infrastructure.logcapture;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

import static java.lang.String.format;

/**
* define expected StructuredArgument.keyValue(...) from logstash with this matcher
*/
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class ExpectedKeyValue implements LogEventMatcher {
static final String LOGSTASH_MARKER_CLASS = "net.logstash.logback.marker.SingleFieldAppendingMarker";
private final String expectedKey;
private final String expectedValue;

@Override
public boolean matches(LoggedEvent loggedEvent) {
failIfLogstashIsNotInClasspath();
return ExpectedKeyValueLogstashDelegate.matches(loggedEvent, expectedKey, expectedValue);
}

@Override
public String getNonMatchingErrorMessage(LoggedEvent loggedEvent) {
failIfLogstashIsNotInClasspath();
return ExpectedKeyValueLogstashDelegate.getNonMatchingErrorMessage(loggedEvent, expectedKey, expectedValue);
}

@Override
public String getMatcherTypeDescription() {
return "key-value content";
}

@Override
public String getMatcherDetailDescription() {
return format("keyValue content with key: \"%s\" and value: \"%s\"", expectedKey, expectedValue);
}

/**
* use this in a log expectation to verify that something has been logged with a keyValue argument from logstashg's StructuredArgument
*
* @param expectedKey expected key
* @param expectedValue expected value
*
* @return expected keyValue to use in log expectation
*/
public static ExpectedKeyValue keyValue(String expectedKey, String expectedValue) {
return new ExpectedKeyValue(expectedKey, expectedValue);
}

/**
* use this in a log expectation to verify that something has been logged with a keyValue argument from logstashg's StructuredArgument
*
* @param expectedKey expected key
* @param expectedValue expected value
*
* @return expected keyValue to use in log expectation
*/
public static ExpectedKeyValue keyValue(String expectedKey, int expectedValue) {
return new ExpectedKeyValue(expectedKey, String.valueOf(expectedValue));
}

/**
* use this in a log expectation to verify that something has been logged with a keyValue argument from logstashg's StructuredArgument
*
* @param expectedKey expected key
* @param expectedValue expected value
*
* @return expected keyValue to use in log expectation
*/
public static ExpectedKeyValue keyValue(String expectedKey, long expectedValue) {
return new ExpectedKeyValue(expectedKey, String.valueOf(expectedValue));
}

private void failIfLogstashIsNotInClasspath() {
try {
Class.forName(LOGSTASH_MARKER_CLASS, false, getClass().getClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("keyValue cannot be used for log assertions if " +
"logstash-logback-encoder that provides StructuredArguments.keyValue(...) is not in the classpath.");
}
}
}
Loading

0 comments on commit 1f18f62

Please sign in to comment.