final AsyncLogger log = (AsyncLogger) LogManager.getLogger("com.foo.Bar"); final long before = System.nanoTime(); log.info("Use actual System.nanoTime()"); assertTrue("using SystemNanoClock", log.getNanoClock() instanceof SystemNanoClock); log.getContext().getConfiguration().setNanoClock(new DummyNanoClock(DUMMYNANOTIME)); log.updateConfiguration(log.getContext().getConfiguration()); log.updateConfiguration(log.getContext().getConfiguration()); log.info("Use dummy nano clock"); assertTrue("using SystemNanoClock", log.getNanoClock() instanceof DummyNanoClock);
@Test public void testAsyncLogWritesToLog() throws Exception { final File file = new File("target", "AsyncLoggerTest.log"); // System.out.println(f.getAbsolutePath()); file.delete(); final AsyncLogger log = (AsyncLogger) LogManager.getLogger("com.foo.Bar"); assertTrue(log.getNanoClock() instanceof DummyNanoClock); final String msg = "Async logger msg"; log.info(msg, new InternalError("this is not a real error")); CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread final BufferedReader reader = new BufferedReader(new FileReader(file)); final String line1 = reader.readLine(); reader.close(); file.delete(); assertNotNull("line1", line1); assertTrue("line1 correct", line1.contains(msg)); final String location = "testAsyncLogWritesToLog"; assertTrue("no location", !line1.contains(location)); }
/** * Enqueues the specified log event data for logging in a background thread. * <p> * This re-uses a {@code RingBufferLogEventTranslator} instance cached in a {@code ThreadLocal} to avoid creating * unnecessary objects with each event. * * @param fqcn fully qualified name of the caller * @param level level at which the caller wants to log the message * @param marker message marker * @param message the log message * @param thrown a {@code Throwable} or {@code null} */ private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) { // Implementation note: this method is tuned for performance. MODIFY WITH CARE! final RingBufferLogEventTranslator translator = getCachedTranslator(); initTranslator(translator, fqcn, level, marker, message, thrown); initTranslatorThreadValues(translator); publish(translator); }
/** * Enqueues the specified log event data for logging in a background thread. * <p> * This creates a new varargs Object array for each invocation, but does not store any non-JDK classes in a * {@code ThreadLocal} to avoid memory leaks in web applications (see LOG4J2-1172). * * @param fqcn fully qualified name of the caller * @param level level at which the caller wants to log the message * @param marker message marker * @param message the log message * @param thrown a {@code Throwable} or {@code null} */ private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) { // Implementation note: candidate for optimization: exceeds 35 bytecodes. final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor(); if (disruptor == null) { LOGGER.error("Ignoring log event after Log4j has been shut down."); return; } // if the Message instance is reused, there is no point in freezing its message here if (!isReused(message)) { InternalAsyncUtil.makeMessageImmutable(message); } // calls the translateTo method on this AsyncLogger disruptor.getRingBuffer().publishEvent(this, this, calcLocationIfRequested(fqcn), fqcn, level, marker, message, thrown); }
@Override public final String logFileName(final String loggerName, final String testStepId) { try (final CloseableThreadContext.Instance logCtx = put(KEY_STEP_ID, testStepId)) { final Logger logger = LogManager.getLogger(loggerName); final Appender appender = ((AsyncLogger) logger).getAppenders().get("opTraceFile"); final String filePtrn = ((RollingRandomAccessFileAppender) appender).getFilePattern(); return filePtrn.contains(LOG_CONFIG_STEP_ID_PTRN) ? filePtrn.replace(LOG_CONFIG_STEP_ID_PTRN, testStepId) : filePtrn; } }
/** * LOG4J2-471: prevent deadlock when RingBuffer is full and object being logged calls Logger.log() from its * toString() method * * @param fqcn fully qualified caller name * @param level log level * @param marker optional marker * @param message log message * @param thrown optional exception */ void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) { // bypass RingBuffer and invoke Appender directly final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy(); strategy.log(this, getName(), fqcn, marker, level, message, thrown); }
/** * Event processor that reads the event from the ringbuffer can call this method. * * @param endOfBatch flag to indicate if this is the last event in a batch from the RingBuffer */ public void execute(final boolean endOfBatch) { this.endOfBatch = endOfBatch; asyncLogger.actualAsyncLog(this); }
@Override protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) { return new AsyncLogger(ctx, name, messageFactory, loggerDisruptor); }
private void publish(final RingBufferLogEventTranslator translator) { if (!loggerDisruptor.tryPublish(translator)) { handleRingBufferFull(translator); } }
private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) { translator.setBasicValues(this, name, marker, fqcn, level, message, // // don't construct ThrowableProxy until required thrown, // needs shallow copy to be fast (LOG4J2-154) ThreadContext.getImmutableStack(), // // location (expensive to calculate) calcLocationIfRequested(fqcn), // CLOCK.currentTimeMillis(), // nanoClock.nanoTime() // ); }
public LogServlet() { logFileNamePatternByName = Arrays.stream(Loggers.class.getFields()) .map( field -> { try { return field.get(null); } catch (final Exception e) { throw new AssertionError(e); } }) .filter(fieldVal -> fieldVal instanceof Logger) .map(o -> (Logger) o) .filter(logger -> logger.getName().startsWith(Loggers.BASE)) .collect( Collectors.toMap( logger -> logger.getName().substring(Loggers.BASE.length()), logger -> ((AsyncLogger) logger) .getAppenders().values().stream() .filter( appender -> appender instanceof RollingRandomAccessFileAppender) .map( appender -> ((RollingRandomAccessFileAppender) appender) .getFilePattern()) .findAny() .orElse(""))); }
@Override public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) { // Implementation note: candidate for optimization: exceeds 35 bytecodes. final AsyncLogger asyncLogger = (AsyncLogger) args[0]; final StackTraceElement location = (StackTraceElement) args[1]; final String fqcn = (String) args[2]; final Level level = (Level) args[3]; final Marker marker = (Marker) args[4]; final Message message = (Message) args[5]; final Throwable thrown = (Throwable) args[6]; // needs shallow copy to be fast (LOG4J2-154) final ContextStack contextStack = ThreadContext.getImmutableStack(); final Thread currentThread = Thread.currentThread(); final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName(); event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown, // config properties are taken care of in the EventHandler thread // in the AsyncLogger#actualAsyncLog method CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()), contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location, CLOCK.currentTimeMillis(), nanoClock.nanoTime()); }