All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.jhipster.test.LogbackRecorder Maven / Gradle / Ivy

/*
 * Copyright 2016-2023 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package tech.jhipster.test;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.AppenderBase;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * Utility, mainly for unit tests, to assert content written to logback. A classical usage would be
 * the following.
 * 

* {@code * LogbackRecorder recorder = LogbackRecorder.forClass(TestedClass.class) * .reset() * .capture(Level.WARN.name()); * // do something that logs * List events = recorder.release().play(); * // perform assertions on the events * } */ @ConditionalOnClass({LoggerContext.class}) public class LogbackRecorder { /** Constant DEFAULT_MUTE=true */ public static final boolean DEFAULT_MUTE = true; /** Constant DEFAULT_LEVEL="ALL" */ public static final String DEFAULT_LEVEL = "ALL"; /** Constant LOGBACK_EXCEPTION_MESSAGE="Expected logback" */ public static final String LOGBACK_EXCEPTION_MESSAGE = "Expected logback"; /** Constant CAPTURE_EXCEPTION_MESSAGE="Already capturing" */ public static final String CAPTURE_EXCEPTION_MESSAGE = "Already capturing"; /** Constant RELEASE_EXCEPTION_MESSAGE="Not currently capturing" */ public static final String RELEASE_EXCEPTION_MESSAGE = "Not currently capturing"; private static final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); private static final Object lock = context.getConfigurationLock(); private static final Map instances = new WeakHashMap<>(32, 0.75F); /** * Create a recorder for a logback logger identified by the class name. Instances of a recorder are cached per logger. * Make sure to reset it before starting capture. * * @param clazz class whose logger as its name * @return the recorder for this class */ public static LogbackRecorder forClass(Class clazz) { return forLogger(context.getLogger(clazz)); } /** * Create a recorder for a logback logger identified by its name. Instances of a recorder are cached per logger. * Make sure to reset it before starting capture. * * @param name the name of the logger * @return the recorder for this class */ public static LogbackRecorder forName(String name) { return forLogger(context.getLogger(name)); } /** * Create a recorder for a logback logger. Instances of a recorder are cached per logger. * Make sure to reset it before starting capture. * * @param logger the logger to record * @return the recorder for this logger */ public static LogbackRecorder forLogger(org.slf4j.Logger logger) { synchronized (instances) { if (!(logger instanceof Logger)) { throw new IllegalArgumentException(LOGBACK_EXCEPTION_MESSAGE); } LogbackRecorder recorder = instances.get(logger); if (recorder == null) { recorder = new LogbackRecorder((Logger) logger); instances.put(recorder.logger, recorder); } return recorder; } } private final Logger logger; private final List events; private final AppenderBase appender; private boolean active; private boolean additive; private Level level; private LogbackRecorder(Logger logger) { this.logger = logger; events = new ArrayList<>(); appender = new AppenderBase() { @Override protected synchronized void append(ILoggingEvent event) { events.add(new Event(event)); } }; } /** * Resets the logger by clearing everything that was recorded so far. * * @return this */ public synchronized LogbackRecorder reset() { events.clear(); return this; } /** * Start capturing whatever is logged for this level of worse. * * @param level the level at which to start capturing * @return this */ public LogbackRecorder capture(String level) { synchronized (lock) { if (active) { throw new IllegalStateException(CAPTURE_EXCEPTION_MESSAGE); } active = true; additive = logger.isAdditive(); logger.setAdditive(false); this.level = logger.getLevel(); logger.setLevel(Level.valueOf(level.toUpperCase())); logger.addAppender(appender); appender.start(); } return this; } /** * Stop recording and detach from the logger. * * @return this */ public synchronized LogbackRecorder release() { synchronized (lock) { if (!active) { throw new IllegalStateException(RELEASE_EXCEPTION_MESSAGE); } appender.stop(); logger.detachAppender(appender); logger.setLevel(level); logger.setAdditive(additive); } active = false; return this; } /** * Return all recorded events. * * @return all recorded events so far */ public List play() { return new ArrayList<>(events); } /** * A recorded event. It contains all information sent to the logger. */ public static final class Event { private final Marker marker; private final String level; private final String message; private final Object[] arguments; private final String thrown; Event(ILoggingEvent event) { List markers = event.getMarkerList(); marker = markers == null || markers.isEmpty() ? null : markers.get(0); level = event.getLevel().toString(); message = event.getMessage(); arguments = event.getArgumentArray(); IThrowableProxy proxy = event.getThrowableProxy(); thrown = proxy == null ? null : proxy.getClassName() + ": " + proxy.getMessage(); } /** * Slf4j market used. * * @return the marker */ public Marker getMarker() { return marker; } /** * Level of the log. * * @return the level */ public String getLevel() { return level; } /** * Message passed to the logger with the original placeholders ('{}'). * * @return the logged message */ public String getMessage() { return message; } /** * The arguments passed to the logger to be used by a placeholder. Logged exceptions are not included. * * @return the parameters passed to the logger */ public Object[] getArguments() { return arguments; } /** * Logged exception passed in argument to the logger or null if none. * * @return the logged exception as {@code exception.getClass().getName() + ": " + exception.getMessage()} */ public String getThrown() { return thrown; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy