Author SHA1 Message Date
iparenteau dfbfcb5882 Merge pull request 'master' (#16) from master into release/1.1
Reviewed-on: #16
2022-09-18 22:51:52 -05:00
16 changed files with 563 additions and 799 deletions

No files matched your search

Vendored
+186 -101
View File
@@ -1,101 +1,186 @@
pipeline { #!groovy
agent any
// Required Jenkins plugins:
options { // https://wiki.jenkins-ci.org/display/JENKINS/Timestamper
buildDiscarder(logRotator(numToKeepStr: '5')) // https://wiki.jenkins-ci.org/display/JENKINS/Static+Code+Analysis+Plug-ins
disableConcurrentBuilds() // https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin ?
skipDefaultCheckout(true) // https://wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin
timestamps() // https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin ?
} // https://wiki.jenkins-ci.org/display/JENKINS/DRY+Plugin ?
// https://wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin
stages { // https://wiki.jenkins-ci.org/display/JENKINS/Javadoc+Plugin
stage('Checkout') { // https://wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin ?
steps {
checkout scm
} init()
}
def branch_name
stage('Set version') { def branch_name_base
steps { def build_number
script { def build_url
String branch = env.BRANCH_NAME def git_commit
if (!branch) { def job_name
error('BRANCH_NAME is unavailable; this pipeline must run as a multibranch job') def tag
} def version
def build_type
env.DEPLOY_BUILD = 'false' def display_name
// A release branch supplies major.minor; Jenkins supplies the patch def init() {
// number so release/2.0 build 1 becomes 2.0.1-RELEASE.
def releaseMatch = branch =~ /^release\/(\d+\.\d+)$/ // Keep the 5 most recent builds
if (releaseMatch.matches()) { properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '5']]])
env.BUILD_VERSION = "${releaseMatch[0][1]}.${env.BUILD_NUMBER}-RELEASE"
env.DEPLOY_BUILD = 'true' build_number = env.BUILD_NUMBER
} else if (branch == 'develop') { build_url = env.BUILD_URL
env.BUILD_VERSION = "develop.${env.BUILD_NUMBER}-SNAPSHOT" job_name = "${env.JOB_NAME}"
env.DEPLOY_BUILD = 'true' branch_name = env.BRANCH_NAME
} else { branch_name_docker = branch_name.replaceAll(/\//,'.')
String safeBranch = branch.replaceAll(/[^A-Za-z0-9._-]/, '-') persist = "/var/lib/jenkins/PERSIST/${branch_name_docker}"
env.BUILD_VERSION = "0.0.${env.BUILD_NUMBER}-${safeBranch}-SNAPSHOT"
} // execute the branch type specific pipeline code
currentBuild.displayName = env.BUILD_VERSION try {
}
if (branch_name.indexOf('release/')==0) build_type='release'
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { if (branch_name.indexOf('feature/')==0) build_type='feature'
sh 'mvn -B org.codehaus.mojo:versions-maven-plugin:2.21.0:set -DgenerateBackupPoms=false -DnewVersion="$BUILD_VERSION"' if (branch_name.indexOf('develop')==0) build_type='develop'
} if (branch_name.indexOf('hotfix')==0) build_type='hotfix'
} if (branch_name.indexOf('bugfix')==0) build_type='bugfix'
} if (branch_name.indexOf('master')==0) build_type='master'
stage('Prepare OWASP cache') { // common pipeline elements
steps { node() {
lock(resource: 'owasp-nvd-cache') { Initialize()
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { SetVersion(build_type)
sh 'mkdir -p "$HOME/.cache/dependency-check"' print_vars() // after SetVersion - all variables now defined
sh 'mvn -B org.owasp:dependency-check-maven:13.0.0:update-only -DdataDirectory="$HOME/.cache/dependency-check"' set_result('INPROGRESS')
} Build() // builds database via flyway migration
} }
}
} if (branch_name.indexOf('develop')==0) {
node() {
stage('Build and test') { Deploy();
steps { }
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { } else if (branch_name.indexOf('release/')==0) {
sh 'mvn -B clean verify -DdataDirectory="$HOME/.cache/dependency-check" -DautoUpdate=false -Dbuild.revision="$GIT_COMMIT"' node() {
} Deploy();
} }
post { }
always {
junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml' node() {
} set_result('SUCCESS')
success { }
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
archiveArtifacts artifacts: '**/target/site/jacoco/**', fingerprint: true } catch (err) {
} node() {
} set_result('FAILURE')
} }
throw err
stage('Deploy') { }
when { }
expression { env.DEPLOY_BUILD == 'true' }
} def Build() {
steps { stage ('build') {
withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { mvn "install -DskipTests=true -Dbuild.revision=${git_commit}"
sh 'mvn -B deploy -DskipTests -Ddependency-check.skip=true -Dbuild.number="$BUILD_NUMBER" -Dbuild.revision="$GIT_COMMIT"' step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])
} }
} }
}
} def Initialize() {
stage ('initialize') {
post {
success { // get new code
echo "Published build ${env.BUILD_VERSION} successfully" checkout scm
}
failure { git_commit = getSha1()
echo "Build ${env.BUILD_VERSION ?: env.BUILD_NUMBER} failed" }
} }
cleanup {
deleteDir() def Deploy() {
} stage ('deploy') {
} mvn "deploy -DskipTests=true -Dbuild.number=${build_number} -Dbuild.revision=${git_commit}"
} }
}
def getSha1() {
sha1 = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
echo "sha1 is ${sha1}"
return sha1
}
def mvn(args) {
withMaven(
maven: 'maven-3.6.1',
globalMavenSettingsConfig: 'locusworks-settings'
) {
sh "mvn ${args}"
}
}
def mvn_initial(args) {
mvn(args)
}
def set_result(status) {
if ( status == 'SUCCESS' ) {
currentBuild.result = status
notify_bitbucket('SUCCESSFUL')
} else if ( status == 'FAILURE' ) {
currentBuild.result = status
notify_bitbucket('FAILED')
} else if ( status == 'INPROGRESS' ) {
notify_bitbucket('INPROGRESS')
} else {
error ("unknown status")
}
// save in persistence file for access the status page
// make sure the directory exists first
sh "mkdir -p $persist && echo $status > $persist/build.result"
}
def notify_bitbucket(state) {
}
def print_vars() {
echo "build_number = ${build_number}"
echo "build_url = ${build_url}"
echo "job_name = ${job_name}"
echo "branch_name = ${branch_name}"
echo "branch_name_base = ${branch_name_base}"
echo "build_type = ${build_type}"
echo "display_name = ${currentBuild.displayName}"
echo "version = ${version}"
echo "git_commit = ${git_commit}"
}
def SetVersion( v ) {
stage ('set version') {
echo "set version ${v}"
branch_name_base = (branch_name =~ /([^\/]+$)/)[0][0]
if ( v == 'release' ) {
// for release branches, where the branch is named "release/1.2.3",
// derive the version and display name derive from the numeric suffix and append the build number
// 3.2.1.100
version = branch_name_base + "." + build_number + "-RELEASE";
//version = branch_name.substring('release/'.length()) + "." + build_number
currentBuild.displayName = version
} else if (v == 'develop') {
version = branch_name_base + "." + build_number + "-SNAPSHOT";
currentBuild.displayName = version
} else {
// for all other branches the version number is 0 with an appended build number
// and for the display name use the jenkins default #n and add the branch name
// #101 - feature/user/foo
//version = '0.' + build_number
version = branch_name_base + "." + build_number
currentBuild.displayName = "#" + build_number + " - " + branch_name_base
}
display_name = currentBuild.displayName
mvn_initial "versions:set -DnewVersion=${version}"
}
}
return this
+14
View File
@@ -0,0 +1,14 @@
# This is a sample build configuration for Java (Maven).
# Check our guides at https://confluence.atlassian.com/x/zd-5Mw for more examples.
# Only use spaces to indent your .yml configuration.
# -----
# You can specify a custom docker image from Docker Hub as your build environment.
image: maven:3.3.9
pipelines:
default:
- step:
caches:
- maven
script: # Modify the commands below to build your repository.
- mvn -B verify # -B batch mode makes Maven less verbose
+156 -197
View File
@@ -1,197 +1,156 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>net.locusworks</groupId> <groupId>net.locusworks</groupId>
<artifactId>applogger</artifactId> <artifactId>applogger</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<name>Application Logger</name> <name>Application Logger</name>
<description>Logger library for applications</description> <description>Logger library for applications</description>
<scm> <scm>
<url>ssh://gitea@gitea.locusworks.net:7999/locusworks/app-logger.git</url> <url>ssh://gitea@gitea.locusworks.net:7999/locusworks/app-logger.git</url>
</scm> </scm>
<organization> <organization>
<name>locusworks</name> <name>locusworks</name>
<url>www.locusworks.net</url> <url>www.locusworks.net</url>
</organization> </organization>
<properties> <properties>
<slf4j.version>2.0.18</slf4j.version> <main.basedir>${project.basedir}</main.basedir>
<junit.version>5.14.4</junit.version> <maven.compiler.source>1.8</maven.compiler.source>
<mockito.version>5.23.0</mockito.version> <maven.compiler.target>1.8</maven.compiler.target>
<jacoco.version>0.8.15</jacoco.version> <log4j.version>2.19.0</log4j.version>
<maven.compiler.source>21</maven.compiler.source> <slf4j.version>2.0.1</slf4j.version>
<maven.compiler.target>21</maven.compiler.target> <nexus.repo>https://nexus.locusworks.net</nexus.repo>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
<nexus.repo>https://nexus.locusworks.net</nexus.repo>
</properties> <build>
<plugins>
<build> <plugin>
<plugins> <groupId>org.apache.maven.plugins</groupId>
<plugin> <artifactId>maven-surefire-plugin</artifactId>
<groupId>org.jacoco</groupId> <version>3.0.0-M7</version>
<artifactId>jacoco-maven-plugin</artifactId> <configuration>
<version>${jacoco.version}</version> <forkMode>always</forkMode>
<executions> </configuration>
<execution> </plugin>
<goals> <plugin>
<goal>prepare-agent</goal> <groupId>org.apache.maven.plugins</groupId>
</goals> <artifactId>maven-compiler-plugin</artifactId>
</execution> <version>3.10.1</version>
<execution> <configuration>
<id>report</id> <source>${maven.compiler.source}</source>
<phase>verify</phase> <target>${maven.compiler.target}</target>
<goals> <failOnError>true</failOnError>
<goal>report</goal> <compilerArgs>
</goals> <arg>-Xlint:all</arg>
</execution> </compilerArgs>
<execution> </configuration>
<id>coverage-check</id> </plugin>
<phase>verify</phase> <plugin>
<goals> <groupId>org.owasp</groupId>
<goal>check</goal> <artifactId>dependency-check-maven</artifactId>
</goals> <version>7.2.0</version>
<configuration> <executions>
<rules> <execution>
<rule> <goals>
<element>BUNDLE</element> <goal>check</goal>
<limits> </goals>
<limit> </execution>
<counter>LINE</counter> </executions>
<value>COVEREDRATIO</value> </plugin>
<minimum>0.75</minimum> <plugin>
</limit> <groupId>org.apache.maven.plugins</groupId>
</limits> <artifactId>maven-enforcer-plugin</artifactId>
</rule> <version>3.1.0</version>
</rules> <executions>
</configuration> <execution>
</execution> <id>enforce</id>
</executions> <configuration>
</plugin> <rules>
<plugin> <DependencyConvergence />
<groupId>org.apache.maven.plugins</groupId> </rules>
<artifactId>maven-surefire-plugin</artifactId> </configuration>
<version>3.5.6</version> <goals>
<configuration> <goal>enforce</goal>
<argLine>@{argLine} -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar</argLine> </goals>
</configuration> </execution>
</plugin> </executions>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> </plugins>
<artifactId>maven-compiler-plugin</artifactId> </build>
<version>3.15.0</version>
<configuration> <dependencies>
<source>${maven.compiler.source}</source> <dependency>
<target>${maven.compiler.target}</target> <groupId>org.apache.logging.log4j</groupId>
<failOnError>true</failOnError> <artifactId>log4j-api</artifactId>
<compilerArgs> <version>${log4j.version}</version>
<arg>-Xlint:all</arg> </dependency>
</compilerArgs> <dependency>
</configuration> <groupId>org.apache.logging.log4j</groupId>
</plugin> <artifactId>log4j-core</artifactId>
<plugin> <version>${log4j.version}</version>
<groupId>org.owasp</groupId> </dependency>
<artifactId>dependency-check-maven</artifactId> <dependency>
<version>13.0.0</version> <groupId>org.apache.logging.log4j</groupId>
<configuration> <artifactId>log4j-slf4j-impl</artifactId>
<skipProvidedScope>true</skipProvidedScope> <version>${log4j.version}</version>
<skipTestScope>true</skipTestScope> <exclusions>
<failOnError>true</failOnError> <exclusion>
<versionCheckEnabled>true</versionCheckEnabled> <groupId>org.slf4j</groupId>
<nvdApiKey>e2eb1036-9b5b-4df9-95e7-0888be947011</nvdApiKey> <artifactId>slf4j-api</artifactId>
</configuration> </exclusion>
<executions> </exclusions>
<execution> </dependency>
<goals> <dependency>
<goal>check</goal> <groupId>org.slf4j</groupId>
</goals> <artifactId>slf4j-api</artifactId>
</execution> <version>${slf4j.version}</version>
</executions> </dependency>
</plugin> <dependency>
<plugin> <groupId>org.slf4j</groupId>
<groupId>org.apache.maven.plugins</groupId> <artifactId>jcl-over-slf4j</artifactId>
<artifactId>maven-enforcer-plugin</artifactId> <version>${slf4j.version}</version>
<version>3.6.3</version> </dependency>
<executions> </dependencies>
<execution>
<id>enforce</id> <distributionManagement>
<configuration> <snapshotRepository>
<rules> <id>nexus-snapshot</id>
<DependencyConvergence /> <url>${nexus.repo}/repository/locusworks-snapshot/</url>
</rules> </snapshotRepository>
</configuration> <repository>
<goals> <id>nexus-release</id>
<goal>enforce</goal> <url>${nexus.repo}/repository/locusworks-release/</url>
</goals> </repository>
</execution> </distributionManagement>
</executions>
</plugin> <repositories>
</plugins> <repository>
</build> <id>locusworks-public</id>
<name>locusworks-public</name>
<dependencies> <url>${nexus.repo}/repository/locusworks-public/</url>
<dependency> <releases>
<groupId>org.slf4j</groupId> <enabled>true</enabled>
<artifactId>slf4j-api</artifactId> </releases>
<version>${slf4j.version}</version> <snapshots>
</dependency> <enabled>true</enabled>
<dependency> </snapshots>
<groupId>org.slf4j</groupId> </repository>
<artifactId>slf4j-simple</artifactId> </repositories>
<version>${slf4j.version}</version>
<scope>test</scope> <pluginRepositories>
</dependency> <pluginRepository>
<dependency> <id>locusworks-public</id>
<groupId>org.junit.jupiter</groupId> <url>${nexus.repo}/repository/locusworks-public/</url>
<artifactId>junit-jupiter</artifactId> <releases>
<version>${junit.version}</version> <enabled>true</enabled>
<scope>test</scope> </releases>
</dependency> <snapshots>
<dependency> <enabled>true</enabled>
<groupId>org.mockito</groupId> </snapshots>
<artifactId>mockito-core</artifactId> </pluginRepository>
<version>${mockito.version}</version> </pluginRepositories>
<scope>test</scope>
</dependency> </project>
</dependencies>
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshot</id>
<url>${nexus.repo}/repository/locusworks-snapshot/</url>
</snapshotRepository>
<repository>
<id>nexus-release</id>
<url>${nexus.repo}/repository/locusworks-release/</url>
</repository>
</distributionManagement>
<repositories>
<repository>
<id>locusworks-public</id>
<name>locusworks-public</name>
<url>${nexus.repo}/repository/locusworks-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>locusworks-public</id>
<url>${nexus.repo}/repository/locusworks-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
@@ -4,9 +4,7 @@ import java.util.Map;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.Marker; import org.slf4j.Marker;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
/** /**
* Logger implementation to use across applications. Extends slf4j logger to work with other logging applications * Logger implementation to use across applications. Extends slf4j logger to work with other logging applications
@@ -15,9 +13,9 @@ import org.slf4j.helpers.MessageFormatter;
*/ */
public class ApplicationLogger implements org.slf4j.Logger { public class ApplicationLogger implements org.slf4j.Logger {
protected static final String DEFAULT_FORMAT = "{}"; protected static final String DEFAULT_FORMAT = "%s";
private final Logger logger; private static final Logger logger = LoggerFactory.getLogger(ApplicationLogger.class);
private final String name; private final String name;
@@ -43,15 +41,10 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param name name of the logger * @param name name of the logger
* @param level level of logging to set the logger to * @param level level of logging to set the logger to
*/ */
protected ApplicationLogger(String name, LogLevel level) { protected ApplicationLogger(String name, LogLevel level) {
this(name, level, LoggerFactory.getLogger(name)); this.name = name;
} this.level = level;
}
ApplicationLogger(String name, LogLevel level, Logger logger) {
this.name = name;
this.level = level;
this.logger = logger;
}
/** /**
* Constructor * Constructor
@@ -111,8 +104,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public boolean isTraceEnabled() { public boolean isTraceEnabled() {
return enabled(LogLevel.TRACE) && logger.isTraceEnabled(); return this.level.log(LogLevel.TRACE);
} }
@Override @Override
@@ -136,43 +129,43 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public void trace(String msg, Throwable t) { public void trace(String msg, Throwable t) {
log(LogLevel.TRACE, msg, t); trace("%s%n%s", msg, getStackTrace(t.getStackTrace()));
} }
@Override @Override
public boolean isTraceEnabled(Marker marker) { public boolean isTraceEnabled(Marker marker) {
return enabled(LogLevel.TRACE) && logger.isTraceEnabled(marker); return isTraceEnabled();
} }
@Override @Override
public void trace(Marker marker, String msg) { public void trace(Marker marker, String msg) {
markerLog(LogLevel.TRACE, marker, msg); trace(msg);
} }
@Override @Override
public void trace(Marker marker, String format, Object arg) { public void trace(Marker marker, String format, Object arg) {
markerLog(LogLevel.TRACE, marker, format, arg); trace(format, arg);
} }
@Override @Override
public void trace(Marker marker, String format, Object arg1, Object arg2) { public void trace(Marker marker, String format, Object arg1, Object arg2) {
markerLog(LogLevel.TRACE, marker, format, arg1, arg2); trace(format, arg1, arg2);
} }
@Override @Override
public void trace(Marker marker, String format, Object... argArray) { public void trace(Marker marker, String format, Object... argArray) {
markerLog(LogLevel.TRACE, marker, format, argArray); trace(format, argArray);
} }
@Override @Override
public void trace(Marker marker, String msg, Throwable t) { public void trace(Marker marker, String msg, Throwable t) {
markerLog(LogLevel.TRACE, marker, msg, t); trace(msg, t);
} }
@Override @Override
public boolean isDebugEnabled() { public boolean isDebugEnabled() {
return enabled(LogLevel.DEBUG) && logger.isDebugEnabled(); return this.level.log(LogLevel.DEBUG);
} }
@Override @Override
@@ -196,43 +189,43 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public void debug(String msg, Throwable t) { public void debug(String msg, Throwable t) {
log(LogLevel.DEBUG, msg, t); debug("%s%n%s", msg, getStackTrace(t.getStackTrace()));
} }
@Override @Override
public boolean isDebugEnabled(Marker marker) { public boolean isDebugEnabled(Marker marker) {
return enabled(LogLevel.DEBUG) && logger.isDebugEnabled(marker); return isDebugEnabled();
} }
@Override @Override
public void debug(Marker marker, String msg) { public void debug(Marker marker, String msg) {
markerLog(LogLevel.DEBUG, marker, msg); debug(msg);
} }
@Override @Override
public void debug(Marker marker, String format, Object arg) { public void debug(Marker marker, String format, Object arg) {
markerLog(LogLevel.DEBUG, marker, format, arg); debug(format, arg);
} }
@Override @Override
public void debug(Marker marker, String format, Object arg1, Object arg2) { public void debug(Marker marker, String format, Object arg1, Object arg2) {
markerLog(LogLevel.DEBUG, marker, format, arg1, arg2); debug(format, arg1, arg2);
} }
@Override @Override
public void debug(Marker marker, String format, Object... arguments) { public void debug(Marker marker, String format, Object... arguments) {
markerLog(LogLevel.DEBUG, marker, format, arguments); debug(format, arguments);
} }
@Override @Override
public void debug(Marker marker, String msg, Throwable t) { public void debug(Marker marker, String msg, Throwable t) {
markerLog(LogLevel.DEBUG, marker, msg, t); debug(msg, t);
} }
@Override @Override
public boolean isInfoEnabled() { public boolean isInfoEnabled() {
return enabled(LogLevel.INFO) && logger.isInfoEnabled(); return this.level.log(LogLevel.INFO);
} }
@Override @Override
@@ -256,8 +249,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public void info(String msg, Throwable t) { public void info(String msg, Throwable t) {
log(LogLevel.INFO, msg, t); info("%s%n%s", msg, getStackTrace(t.getStackTrace()));
} }
/** /**
@@ -289,38 +282,38 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public boolean isInfoEnabled(Marker marker) { public boolean isInfoEnabled(Marker marker) {
return enabled(LogLevel.INFO) && logger.isInfoEnabled(marker); return isInfoEnabled();
} }
@Override @Override
public void info(Marker marker, String msg) { public void info(Marker marker, String msg) {
markerLog(LogLevel.INFO, marker, msg); info(msg);
} }
@Override @Override
public void info(Marker marker, String format, Object arg) { public void info(Marker marker, String format, Object arg) {
markerLog(LogLevel.INFO, marker, format, arg); info(format, arg);
} }
@Override @Override
public void info(Marker marker, String format, Object arg1, Object arg2) { public void info(Marker marker, String format, Object arg1, Object arg2) {
markerLog(LogLevel.INFO, marker, format, arg1, arg2); info(format, arg1, arg2);
} }
@Override @Override
public void info(Marker marker, String format, Object... arguments) { public void info(Marker marker, String format, Object... arguments) {
markerLog(LogLevel.INFO, marker, format, arguments); info(format, arguments);
} }
@Override @Override
public void info(Marker marker, String msg, Throwable t) { public void info(Marker marker, String msg, Throwable t) {
markerLog(LogLevel.INFO, marker, msg, t); info(msg, t);
} }
@Override @Override
public boolean isWarnEnabled() { public boolean isWarnEnabled() {
return enabled(LogLevel.WARN) && logger.isWarnEnabled(); return this.level.log(LogLevel.WARN);
} }
@Override @Override
@@ -344,38 +337,38 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public void warn(String msg, Throwable t) { public void warn(String msg, Throwable t) {
log(LogLevel.WARN, msg, t); warn("%s%n%s", msg, getStackTrace(t.getStackTrace()));
} }
@Override @Override
public boolean isWarnEnabled(Marker marker) { public boolean isWarnEnabled(Marker marker) {
return enabled(LogLevel.WARN) && logger.isWarnEnabled(marker); return isWarnEnabled();
} }
@Override @Override
public void warn(Marker marker, String msg) { public void warn(Marker marker, String msg) {
markerLog(LogLevel.WARN, marker, msg); warn(msg);
} }
@Override @Override
public void warn(Marker marker, String format, Object arg) { public void warn(Marker marker, String format, Object arg) {
markerLog(LogLevel.WARN, marker, format, arg); warn(format, arg);
} }
@Override @Override
public void warn(Marker marker, String format, Object arg1, Object arg2) { public void warn(Marker marker, String format, Object arg1, Object arg2) {
markerLog(LogLevel.WARN, marker, format, arg1, arg2); warn(format, arg1, arg2);
} }
@Override @Override
public void warn(Marker marker, String format, Object... arguments) { public void warn(Marker marker, String format, Object... arguments) {
markerLog(LogLevel.WARN, marker, format, arguments); warn(format, arguments);
} }
@Override @Override
public void warn(Marker marker, String msg, Throwable t) { public void warn(Marker marker, String msg, Throwable t) {
markerLog(LogLevel.WARN, marker, msg, t); warn(msg, t);
} }
/** /**
@@ -406,8 +399,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public boolean isErrorEnabled() { public boolean isErrorEnabled() {
return enabled(LogLevel.ERROR) && logger.isErrorEnabled(); return this.level.log(LogLevel.ERROR);
} }
@Override @Override
@@ -435,8 +428,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
} }
@Override @Override
public void error(String msg, Throwable t) { public void error(String msg, Throwable t) {
log(LogLevel.ERROR, msg, t); error("%s%n%s", msg, getStackTrace(t.getStackTrace()));
} }
/** /**
@@ -454,8 +447,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param sb String builder to append message to * @param sb String builder to append message to
* @param e throwable error to log * @param e throwable error to log
*/ */
public void error(Map<String, String> values, StringBuilder sb, Throwable e) { public void error(Map<String, String> values, StringBuilder sb, Throwable e) {
error(values, null, sb, e); error(values, null, sb);
} }
/** /**
@@ -475,38 +468,41 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param sb string builder to append messages to * @param sb string builder to append messages to
* @param e Throwable error to log * @param e Throwable error to log
*/ */
public void error(Map<String, String> values, String valueFormat, StringBuilder sb, Throwable e) { public void error(Map<String, String> values, String valueFormat, StringBuilder sb, Throwable e) {
log(LogLevel.ERROR, formatValues(values, valueFormat, sb), e); msgHelper(LogLevel.ERROR, values, valueFormat, sb);
if (e != null) {
msgHelper(LogLevel.ERROR,"", e);
}
} }
@Override @Override
public boolean isErrorEnabled(Marker marker) { public boolean isErrorEnabled(Marker marker) {
return enabled(LogLevel.ERROR) && logger.isErrorEnabled(marker); return isErrorEnabled();
} }
@Override @Override
public void error(Marker marker, String msg) { public void error(Marker marker, String msg) {
markerLog(LogLevel.ERROR, marker, msg); error(msg);
} }
@Override @Override
public void error(Marker marker, String format, Object arg) { public void error(Marker marker, String format, Object arg) {
markerLog(LogLevel.ERROR, marker, format, arg); error(format, arg);
} }
@Override @Override
public void error(Marker marker, String format, Object arg1, Object arg2) { public void error(Marker marker, String format, Object arg1, Object arg2) {
markerLog(LogLevel.ERROR, marker, format, arg1, arg2); error(format, arg1, arg2);
} }
@Override @Override
public void error(Marker marker, String format, Object... arguments) { public void error(Marker marker, String format, Object... arguments) {
markerLog(LogLevel.ERROR, marker, format, arguments); error(format, arguments);
} }
@Override @Override
public void error(Marker marker, String msg, Throwable t) { public void error(Marker marker, String msg, Throwable t) {
markerLog(LogLevel.ERROR, marker, msg, t); error(msg, t);
} }
/** /**
@@ -514,7 +510,7 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param level log level to use * @param level log level to use
* @param message message to log * @param message message to log
*/ */
protected void log(LogLevel level, String message) { protected void log(LogLevel level, String message) {
if (level == null ||this.level == null || level.toInt() < this.level.toInt()) return; if (level == null ||this.level == null || level.toInt() < this.level.toInt()) return;
switch (level) { switch (level) {
@@ -539,43 +535,7 @@ public class ApplicationLogger implements org.slf4j.Logger {
default: default:
break; break;
} }
} }
private boolean enabled(LogLevel messageLevel) {
LogLevel current = this.level;
return current != null && current != LogLevel.OFF && messageLevel.toInt() >= current.toInt();
}
protected void log(LogLevel level, String message, Throwable throwable) {
if (level == null || this.level == null || level.toInt() < this.level.toInt()) return;
switch (level) {
case ALL:
case TRACE: logger.trace(message, throwable); break;
case DEBUG: logger.debug(message, throwable); break;
case INFO: logger.info(message, throwable); break;
case WARN: logger.warn(message, throwable); break;
case ERROR:
case FATAL: logger.error(message, throwable); break;
case OFF:
default: break;
}
}
private void markerLog(LogLevel level, Marker marker, String message, Object... arguments) {
if (level == null || this.level == null || level.toInt() < this.level.toInt()) return;
FormattingTuple tuple = MessageFormatter.arrayFormat(message, arguments);
switch (level) {
case ALL:
case TRACE: logger.trace(marker, tuple.getMessage(), tuple.getThrowable()); break;
case DEBUG: logger.debug(marker, tuple.getMessage(), tuple.getThrowable()); break;
case INFO: logger.info(marker, tuple.getMessage(), tuple.getThrowable()); break;
case WARN: logger.warn(marker, tuple.getMessage(), tuple.getThrowable()); break;
case ERROR:
case FATAL: logger.error(marker, tuple.getMessage(), tuple.getThrowable()); break;
case OFF:
default: break;
}
}
/** /**
* Print the exception stack trace to a string * Print the exception stack trace to a string
@@ -606,13 +566,11 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param valueFormat value format to map values as * @param valueFormat value format to map values as
* @param sb String builder to append messages to * @param sb String builder to append messages to
*/ */
private void msgHelper(LogLevel level, Map<String, String> values, String valueFormat, StringBuilder sb) { private void msgHelper(LogLevel level, Map<String, String> values, String valueFormat, StringBuilder sb) {
log(level, formatValues(values, valueFormat, sb));
} if (sb == null) {
sb = new StringBuilder();
private String formatValues(Map<String, String> values, String valueFormat, StringBuilder sb) { }
if (values == null) throw new IllegalArgumentException("values must not be null");
if (sb == null) sb = new StringBuilder();
if (valueFormat == null || valueFormat.trim().isEmpty()) { if (valueFormat == null || valueFormat.trim().isEmpty()) {
int longest = 0; int longest = 0;
@@ -632,8 +590,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
.map(entry -> String.format(format, entry.getKey(), entry.getValue())) .map(entry -> String.format(format, entry.getKey(), entry.getValue()))
.forEach(builder::append); .forEach(builder::append);
return builder.toString(); log(level, builder.toString());
} }
/** /**
* Help format a message for logging * Help format a message for logging
@@ -641,9 +599,8 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param format The string format to use * @param format The string format to use
* @param args Arguments to use in the string format * @param args Arguments to use in the string format
*/ */
private void msgHelper(LogLevel level, String format, Object...args) { private void msgHelper(LogLevel level, String format, Object...args) {
FormattingTuple tuple = MessageFormatter.arrayFormat(format, args); log(level, String.format(format, args));
log(level, tuple.getMessage(), tuple.getThrowable());
} }
/** /**
@@ -662,7 +619,7 @@ public class ApplicationLogger implements org.slf4j.Logger {
* @param message the message to log * @param message the message to log
* @return the formatted string * @return the formatted string
*/ */
private String format(String message, LogLevel level) { private String format(String message, LogLevel level) {
return String.format("th%06d [%-5s] [%s] %s", Thread.currentThread().threadId(), level, this.name, message); return String.format("th%06d [%-5s] [%s] %s", Thread.currentThread().getId(), level, this.name, message);
} }
} }
@@ -2,7 +2,7 @@ package net.locusworks.logger;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.TreeMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/*** /***
@@ -12,9 +12,9 @@ import java.util.stream.Collectors;
* @date 02/15/2018 * @date 02/15/2018
*/ */
public class ApplicationLoggerFactory { public class ApplicationLoggerFactory {
private static final Map<String, ApplicationLogger> loggers = new ConcurrentHashMap<>(); private static Map<String, ApplicationLogger> loggers = new TreeMap<>();
private static volatile LogLevel defaultLevel = LogLevel.ALL; private static LogLevel DEFAULT_LEVEL = LogLevel.ALL;
private static volatile ApplicationLoggerInitializer initializer; private static ApplicationLoggerInitializer initializer;
/** /**
* Need to get the log level from the properties file. * Need to get the log level from the properties file.
@@ -24,8 +24,7 @@ public class ApplicationLoggerFactory {
*/ */
public static void init(ApplicationLoggerInitializer init) { public static void init(ApplicationLoggerInitializer init) {
initializer = init; initializer = init;
LogLevel initializedLevel = initializer == null ? LogLevel.INFO : initializer.initialize(); DEFAULT_LEVEL = initializer == null ? LogLevel.INFO : initializer.initialize();
defaultLevel = initializedLevel == null ? LogLevel.INFO : initializedLevel;
loadLoggers(); loadLoggers();
} }
@@ -61,7 +60,7 @@ public class ApplicationLoggerFactory {
* @return * @return
*/ */
private static LogLevel getDefaultLevel() { private static LogLevel getDefaultLevel() {
return defaultLevel; return DEFAULT_LEVEL;
} }
/** /**
@@ -71,8 +70,10 @@ public class ApplicationLoggerFactory {
* @return the logger represented by the given name * @return the logger represented by the given name
*/ */
public static ApplicationLogger getLogger(String name, LogLevel level) { public static ApplicationLogger getLogger(String name, LogLevel level) {
ApplicationLogger logger = loggers.computeIfAbsent(name, if (!loggers.containsKey(name)) {
loggerName -> new ApplicationLogger(loggerName, level == null ? getDefaultLevel() : level)); loggers.put(name, new ApplicationLogger(name, level));
}
ApplicationLogger logger = loggers.get(name);
if (initializer != null) { if (initializer != null) {
initializer.postGetLogger(logger.getName(), logger.getLogLevel().toName()); initializer.postGetLogger(logger.getName(), logger.getLogLevel().toName());
} }
@@ -1,60 +0,0 @@
package net.locusworks.logger;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;
/** Buffers redirected output so each complete UTF-8 line becomes one log event. */
final class LineLoggingOutputStream extends OutputStream {
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final Consumer<String> sink;
LineLoggingOutputStream(Consumer<String> sink) {
this.sink = sink;
}
@Override
public synchronized void write(int value) {
if (value == '\n') {
emit();
} else {
buffer.write(value);
}
}
@Override
public synchronized void write(byte[] bytes, int offset, int length) {
int end = offset + length;
int start = offset;
for (int index = offset; index < end; index++) {
if (bytes[index] == '\n') {
buffer.write(bytes, start, index - start);
emit();
start = index + 1;
}
}
buffer.write(bytes, start, end - start);
}
@Override
public synchronized void flush() {
if (buffer.size() > 0) emit();
}
@Override
public void close() throws IOException {
flush();
super.close();
}
private void emit() {
byte[] bytes = buffer.toByteArray();
buffer.reset();
int length = bytes.length;
if (length > 0 && bytes[length - 1] == '\r') length--;
sink.accept(new String(bytes, 0, length, UTF_8));
}
}
@@ -16,10 +16,10 @@ public enum LogLevel {
TRACE(1, "TRACE"), TRACE(1, "TRACE"),
ALL(0, "ALL"); ALL(0, "ALL");
private final int intLevel; private Integer intLevel;
private final String levelName; private String levelName;
LogLevel(int intLevel, String levelName) { private LogLevel(Integer intLevel, String levelName) {
this.intLevel = intLevel; this.intLevel = intLevel;
this.levelName = levelName; this.levelName = levelName;
} }
@@ -41,7 +41,7 @@ public enum LogLevel {
* Get the integer representation of the log level * Get the integer representation of the log level
* @return intLevel * @return intLevel
*/ */
public int toInt() { public Integer toInt() {
return this.intLevel; return this.intLevel;
} }
@@ -64,7 +64,7 @@ public enum LogLevel {
*/ */
public static LogLevel getEnum(Integer level) { public static LogLevel getEnum(Integer level) {
for (LogLevel l : values()) { for (LogLevel l : values()) {
if (level != null && l.toInt() == level) { if (l.toInt().equals(level)) {
return l; return l;
} }
} }
@@ -77,7 +77,6 @@ public enum LogLevel {
* @return the log level for the name or null if it cant be found * @return the log level for the name or null if it cant be found
*/ */
public static LogLevel getEnum(String levelName) { public static LogLevel getEnum(String levelName) {
if (levelName == null) return null;
for (LogLevel l : values()) { for (LogLevel l : values()) {
if (l.toName().equalsIgnoreCase(levelName)) { if (l.toName().equalsIgnoreCase(levelName)) {
return l; return l;
@@ -85,4 +84,4 @@ public enum LogLevel {
} }
return null; return null;
} }
} }
@@ -1,15 +1,36 @@
package net.locusworks.logger; package net.locusworks.logger;
import java.io.PrintStream; import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@ApplicationLoggerInfo(name="System.Debug", defaultLevel=LogLevel.DEBUG) @ApplicationLoggerInfo(name="System.Debug", defaultLevel=LogLevel.DEBUG)
public class SystemDebugLogger extends PrintStream { public class SystemDebugLogger extends PrintStream {
private ApplicationLogger logger;
public SystemDebugLogger() { public SystemDebugLogger() {
this(ApplicationLoggerFactory.getLogger(SystemDebugLogger.class)); this(ApplicationLoggerFactory.getLogger(SystemDebugLogger.class));
} }
public SystemDebugLogger(ApplicationLogger logger) { public SystemDebugLogger(ApplicationLogger logger) {
super(new LineLoggingOutputStream(logger::debug), true); super(new ByteArrayOutputStream());
} this.logger = logger;
} }
@Override
public void write(byte[] b) {
logger.debug(new String(b, UTF_8));
}
@Override
public void write(byte[] b, int off, int len) {
logger.debug(new String(b, off, len, UTF_8));
}
@Override
public void write(int b) {
write(new byte[] { (byte)b });
}
}
@@ -1,15 +1,36 @@
package net.locusworks.logger; package net.locusworks.logger;
import java.io.PrintStream; import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@ApplicationLoggerInfo(name="System.Err", defaultLevel=LogLevel.ERROR) @ApplicationLoggerInfo(name="System.Err", defaultLevel=LogLevel.ERROR)
public class SystemErrLogger extends PrintStream { public class SystemErrLogger extends PrintStream {
private ApplicationLogger logger;
public SystemErrLogger() { public SystemErrLogger() {
this(ApplicationLoggerFactory.getLogger(SystemErrLogger.class)); this(ApplicationLoggerFactory.getLogger(SystemErrLogger.class));
} }
public SystemErrLogger(ApplicationLogger logger) { public SystemErrLogger(ApplicationLogger logger) {
super(new LineLoggingOutputStream(logger::error), true); super(new ByteArrayOutputStream());
} this.logger = logger;
} }
@Override
public void write(byte[] b) {
logger.error(new String(b, UTF_8));
}
@Override
public void write(byte[] b, int off, int len) {
logger.error(new String(b, off, len, UTF_8));
}
@Override
public void write(int b) {
write(new byte[] { (byte)b });
}
}
@@ -1,15 +1,36 @@
package net.locusworks.logger; package net.locusworks.logger;
import java.io.PrintStream; import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@ApplicationLoggerInfo(name="System.Out", defaultLevel=LogLevel.OFF) @ApplicationLoggerInfo(name="System.Out", defaultLevel=LogLevel.OFF)
public class SystemOutLogger extends PrintStream { public class SystemOutLogger extends PrintStream {
private ApplicationLogger logger;
public SystemOutLogger() { public SystemOutLogger() {
this(ApplicationLoggerFactory.getLogger(SystemOutLogger.class)); this(ApplicationLoggerFactory.getLogger(SystemOutLogger.class));
} }
public SystemOutLogger(ApplicationLogger logger) { public SystemOutLogger(ApplicationLogger logger) {
super(new LineLoggingOutputStream(logger::info), true); super(new ByteArrayOutputStream());
} this.logger = logger;
} }
@Override
public void write(byte[] b) {
logger.info(new String(b, UTF_8));
}
@Override
public void write(byte[] b, int off, int len) {
logger.info(new String(b, off, len, UTF_8));
}
@Override
public void write(int b) {
write(new byte[] { (byte)b });
}
}
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{dd-MMM-yyyy HH:mm:ss.SSS} %m%n" />
</Console>
<RollingFile name="application" fileName="application.log"
filePattern="$${date:yyyy-MM}/${name}-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{dd-MMM-yyyy HH:mm:ss.SSS} %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="application" />
</Root>
</Loggers>
</Configuration>
@@ -1,101 +0,0 @@
package net.locusworks.logger;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.*;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.Marker;
class ApplicationLoggerDelegationTest {
@Test
void delegatesFormattingMarkersAndThrowablesAtEveryLevel() {
Logger delegate = mock(Logger.class);
Marker marker = mock(Marker.class);
RuntimeException failure = new RuntimeException("boom");
when(delegate.getName()).thenReturn("test");
when(delegate.isTraceEnabled()).thenReturn(true);
when(delegate.isDebugEnabled()).thenReturn(true);
when(delegate.isInfoEnabled()).thenReturn(true);
when(delegate.isWarnEnabled()).thenReturn(true);
when(delegate.isErrorEnabled()).thenReturn(true);
when(delegate.isTraceEnabled(marker)).thenReturn(true);
when(delegate.isDebugEnabled(marker)).thenReturn(true);
when(delegate.isInfoEnabled(marker)).thenReturn(true);
when(delegate.isWarnEnabled(marker)).thenReturn(true);
when(delegate.isErrorEnabled(marker)).thenReturn(true);
ApplicationLogger logger = new ApplicationLogger("test", LogLevel.ALL, delegate);
assertEquals("test", logger.getName());
assertTrue(logger.isTraceEnabled());
assertTrue(logger.isDebugEnabled(marker));
assertTrue(logger.isInfoEnabled());
assertTrue(logger.isWarnEnabled(marker));
assertTrue(logger.isErrorEnabled());
logger.trace("trace {}", 1);
logger.trace("trace {} {}", 1, 2);
logger.trace("trace {}", new Object[] {1});
logger.trace("trace failure", failure);
logger.debug("debug {}", 1);
logger.debug("debug {} {}", 1, 2);
logger.debug("debug {}", new Object[] {1});
logger.debug("debug failure", failure);
logger.info("info {}", 1);
logger.info("info {} {}", 1, 2);
logger.info("info {}", new Object[] {1});
logger.info("info failure", failure);
logger.warn("warn {}", 1);
logger.warn("warn {} {}", 1, 2);
logger.warn("warn {}", new Object[] {1});
logger.warn("warn failure", failure);
logger.error("error {}", 1);
logger.error("error {} {}", 1, 2);
logger.error("error {}", new Object[] {1});
logger.error("error failure", failure);
logger.error(failure);
logger.trace(marker, "trace {}", 1);
logger.trace(marker, "trace {} {}", 1, 2);
logger.trace(marker, "trace", new Object[0]);
logger.trace(marker, "trace failure", failure);
logger.debug(marker, "debug {}", 1);
logger.debug(marker, "debug {} {}", 1, 2);
logger.debug(marker, "debug", new Object[0]);
logger.debug(marker, "debug failure", failure);
logger.info(marker, "info {}", 1);
logger.info(marker, "info {} {}", 1, 2);
logger.info(marker, "info", new Object[0]);
logger.info(marker, "info failure", failure);
logger.warn(marker, "warn {}", 1);
logger.warn(marker, "warn {} {}", 1, 2);
logger.warn(marker, "warn", new Object[0]);
logger.warn(marker, "warn failure", failure);
logger.error(marker, "error {}", 1);
logger.error(marker, "error {} {}", 1, 2);
logger.error(marker, "error", new Object[0]);
logger.error(marker, "error failure", failure);
Map<String, String> values = new LinkedHashMap<>();
values.put("a", "one");
values.put("long", "two");
logger.info(values);
logger.warn(values, new StringBuilder("prefix"));
logger.error(values, "%s=%s", new StringBuilder(), failure);
verify(delegate, atLeastOnce()).info(contains("info 1"), org.mockito.ArgumentMatchers.isNull(Throwable.class));
verify(delegate).error("error failure", failure);
verify(delegate).error(marker, "error failure", failure);
verify(delegate).error(contains("a=one"), same(failure));
logger.setLogLevel(LogLevel.OFF);
assertEquals(LogLevel.OFF, logger.getLogLevel());
assertFalse(logger.isErrorEnabled());
logger.error("not logged");
verify(delegate, never()).error(contains("not logged"));
}
}
@@ -1,51 +0,0 @@
package net.locusworks.logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import org.junit.jupiter.api.Test;
class ApplicationLoggerFactoryTest {
@ApplicationLoggerInfo(name = "annotated-name", defaultLevel = LogLevel.WARN)
private static final class AnnotatedType { }
@Test
void initializesLoadsConfiguresAndSavesLoggers() {
ApplicationLoggerInitializer initializer = mock(ApplicationLoggerInitializer.class);
when(initializer.initialize()).thenReturn(LogLevel.DEBUG);
ApplicationLoggerFactory.init(initializer);
verify(initializer).loadLoggers();
ApplicationLogger annotated = ApplicationLoggerFactory.getLogger(AnnotatedType.class);
assertEquals("annotated-name", annotated.getName());
assertEquals(LogLevel.WARN, annotated.getLogLevel());
verify(initializer).postGetLogger("annotated-name", "WARN");
ApplicationLoggerFactory.setLogLevels(List.of(new ApplicationLoggerFactory.LoggerInfo("annotated-name", "ERROR")));
assertEquals(LogLevel.ERROR, annotated.getLogLevel());
ApplicationLogger added = new ApplicationLogger("added-test", LogLevel.INFO);
ApplicationLoggerFactory.addLogger(added);
assertSame(added, ApplicationLoggerFactory.getLogger("added-test"));
ApplicationLoggerFactory.addLoggers(List.of(new ApplicationLoggerFactory.LoggerInfo("list-test", "TRACE")));
assertEquals(LogLevel.TRACE, ApplicationLoggerFactory.getLogger("list-test").getLogLevel());
ApplicationLoggerFactory.saveLogLevels();
verify(initializer).saveLogLevels(anyMap());
ApplicationLoggerFactory.loadLoggers(null);
ApplicationLoggerFactory.saveLogLevels(null);
}
@Test
void loggerInfoSupportsBeanAccess() {
ApplicationLoggerFactory.LoggerInfo info = new ApplicationLoggerFactory.LoggerInfo();
info.setLogger("logger");
info.setLevel("INFO");
assertEquals("logger", info.getLogger());
assertEquals("INFO", info.getLevel());
}
}
@@ -1,65 +0,0 @@
package net.locusworks.logger;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Test;
class ApplicationLoggerTest {
@Test
void filtersMessagesBelowConfiguredLevel() {
ApplicationLogger logger = new ApplicationLogger("level-test", LogLevel.INFO);
assertTrue(logger.isInfoEnabled());
assertFalse(logger.isDebugEnabled());
}
@Test
void factoryReturnsOneInstanceUnderConcurrency() {
List<ApplicationLogger> results = IntStream.range(0, 100).parallel()
.mapToObj(i -> ApplicationLoggerFactory.getLogger("concurrent-test"))
.toList();
results.forEach(logger -> assertSame(results.get(0), logger));
}
@Test
void supportsSlf4jFormattingAndPreservesThrowable() throws Exception {
PrintStream original = System.err;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (PrintStream capture = new PrintStream(output, true, UTF_8)) {
System.setErr(capture);
ApplicationLogger logger = new ApplicationLogger("format-test", LogLevel.INFO);
IllegalStateException failure = new IllegalStateException("failure-detail");
logger.info("Hello {}", "world");
logger.error("Operation failed", failure);
} finally {
System.setErr(original);
}
String logged = output.toString(UTF_8);
assertTrue(logged.contains("Hello world"));
assertTrue(logged.contains("IllegalStateException: failure-detail"));
}
@Test
void systemStreamBuffersUtf8ByLine() {
CapturingLogger logger = new CapturingLogger();
try (PrintStream stream = new SystemOutLogger(logger)) {
byte[] text = "héllo\nsecond\n".getBytes(UTF_8);
for (byte value : text) stream.write(value);
}
assertEquals(List.of("héllo", "second"), logger.messages);
}
private static final class CapturingLogger extends ApplicationLogger {
private final List<String> messages = new ArrayList<>();
private CapturingLogger() { super("capture", LogLevel.ALL); }
@Override public void info(String message) { messages.add(message); }
}
}
@@ -1,26 +0,0 @@
package net.locusworks.logger;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class LogLevelTest {
@Test
void convertsNamesAndNumbers() {
for (LogLevel level : LogLevel.values()) {
assertEquals(level, LogLevel.getEnum(level.toInt()));
assertEquals(level, LogLevel.getEnum(level.toName().toLowerCase()));
assertEquals(level.toName(), level.toString());
}
assertNull(LogLevel.getEnum(99));
assertNull(LogLevel.getEnum((Integer) null));
assertNull(LogLevel.getEnum("unknown"));
assertNull(LogLevel.getEnum((String) null));
}
@Test
void comparesSeverityAndHandlesNull() {
assertTrue(LogLevel.INFO.log(LogLevel.DEBUG));
assertFalse(LogLevel.DEBUG.log(LogLevel.INFO));
assertFalse(LogLevel.INFO.log(null));
}
}
@@ -1,35 +0,0 @@
package net.locusworks.logger;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.io.PrintStream;
import org.junit.jupiter.api.Test;
class SystemLoggerTest {
@Test
void routesCompleteLinesToTheirConfiguredLevels() {
ApplicationLogger logger = mock(ApplicationLogger.class);
try (PrintStream out = new SystemOutLogger(logger);
PrintStream err = new SystemErrLogger(logger);
PrintStream debug = new SystemDebugLogger(logger)) {
out.print("out\r\n");
err.print("err\n");
debug.print("debug");
debug.flush();
}
verify(logger).info("out");
verify(logger).error("err");
verify(logger).debug("debug");
}
@Test
void preservesUtf8SplitAcrossIndividualWrites() {
ApplicationLogger logger = mock(ApplicationLogger.class);
try (PrintStream out = new SystemOutLogger(logger)) {
for (byte value : "h\u00e9llo\n".getBytes(UTF_8)) out.write(value);
}
verify(logger).info("h\u00e9llo");
}
}