Skip to content

Commit

Permalink
fix issues/710
Browse files Browse the repository at this point in the history
Signed-off-by: Ceki Gulcu <[email protected]>
  • Loading branch information
ceki committed Feb 2, 2024
1 parent 432cd9c commit 5a36133
Showing 1 changed file with 84 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
* Logback: the reliable, generic, fast and flexible logging framework. Copyright (C) 1999-2015, QOS.ch. All rights
* reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
* This program and the accompanying materials are dual-licensed under either the terms of the Eclipse Public License
* v1.0 as published by the Eclipse Foundation
*
* or (per the licensee's choosing)
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
* under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.
*/
package ch.qos.logback.classic.spi;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Clock;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.util.EnvUtil;
import org.slf4j.Marker;
import org.slf4j.event.KeyValuePair;
import org.slf4j.helpers.MessageFormatter;
Expand All @@ -34,26 +36,27 @@
import ch.qos.logback.core.spi.SequenceNumberGenerator;

/**
* The internal representation of logging events. When an affirmative decision
* is made to log then a <code>LoggingEvent</code> instance is created. This
* instance is passed around to the different logback-classic components.
* The internal representation of logging events. When an affirmative decision is made to log then a
* <code>LoggingEvent</code> instance is created. This instance is passed around to the different logback-classic
* components.
* <p/>
* <p>
* Writers of logback-classic components such as appenders should be aware of
* that some of the LoggingEvent fields are initialized lazily. Therefore, an
* appender wishing to output data to be later correctly read by a receiver,
* must initialize "lazy" fields prior to writing them out. See the
* {@link #prepareForDeferredProcessing()} method for the exact list.
* Writers of logback-classic components such as appenders should be aware of that some of the LoggingEvent fields are
* initialized lazily. Therefore, an appender wishing to output data to be later correctly read by a receiver, must
* initialize "lazy" fields prior to writing them out. See the {@link #prepareForDeferredProcessing()} method for the
* exact list.
* </p>
*
* @author Ceki G&uuml;lc&uuml;
* @author S&eacute;bastien Pennec
*/
public class LoggingEvent implements ILoggingEvent {

public static final String VIRTUAL_THREAD_NAME_PREFIX = "virtual-";
public static final String REGULAR_UNNAMED_THREAD_PREFIX = "unnamed-";

/**
* Fully qualified name of the calling Logger class. This field does not survive
* serialization.
* Fully qualified name of the calling Logger class. This field does not survive serialization.
* <p/>
* <p/>
* Note that the getCallerInformation() method relies on this fact.
Expand All @@ -73,8 +76,7 @@ public class LoggingEvent implements ILoggingEvent {
* Level of logging event.
* <p/>
* <p>
* This field should not be accessed directly. You should use the
* {@link #getLevel} method instead.
* This field should not be accessed directly. You should use the {@link #getLevel} method instead.
* </p>
*/
private transient Level level;
Expand Down Expand Up @@ -102,8 +104,7 @@ public class LoggingEvent implements ILoggingEvent {
List<KeyValuePair> keyValuePairs;

/**
* The number of milliseconds elapsed from 1/1/1970 until logging event was
* created.
* The number of milliseconds elapsed from 1/1/1970 until logging event was created.
*/
private Instant instant;

Expand Down Expand Up @@ -205,11 +206,56 @@ public void setLoggerName(String loggerName) {

public String getThreadName() {
if (threadName == null) {
threadName = (Thread.currentThread()).getName();
threadName = extractThreadName(Thread.currentThread());
}
return threadName;
}

/**
* Extracts the name of aThread by calling {@link Thread#getName()}. If the value is null, then use the value
* returned by {@link Thread#getId()} prefixing with {@link #VIRTUAL_THREAD_NAME_PREFIX} if thread is virtual or
* with {@link #REGULAR_UNNAMED_THREAD_PREFIX} if regular.
*
* @param aThread
* @return
* @since 1.5.0
*/
private String extractThreadName(Thread aThread) {
if (aThread == null) {
return CoreConstants.NA;
}
String threadName = aThread.getName();
if (threadName != null)
return threadName;
Long virtualThreadId = getVirtualThreadId(aThread);
if (virtualThreadId != null) {
return VIRTUAL_THREAD_NAME_PREFIX + virtualThreadId;
} else {
return REGULAR_UNNAMED_THREAD_PREFIX + aThread.getId();
}
}
// +

/**
* Return the threadId if running under JDK 21+ and the thread is a virtual thread, return null otherwise.
*
* @param aThread
* @return Return the threadId if the thread is a virtual thread, return null otherwise.
*/
Long getVirtualThreadId(Thread aThread) {
if (EnvUtil.isJDK21OrHigher()) {
try {
Method isVirtualMethod = Thread.class.getMethod("isVirtual");
boolean isVirtual = (boolean) isVirtualMethod.invoke(aThread);
if (isVirtual)
return aThread.getId();
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
return null;
}
}
return null;
}

/**
* @param threadName The threadName to set.
* @throws IllegalStateException If threadName has been already set.
Expand Down Expand Up @@ -241,12 +287,12 @@ public void setThrowableProxy(ThrowableProxy tp) {
}

/**
* This method should be called prior to serializing an event. It should also be
* called when using asynchronous or deferred logging.
* This method should be called prior to serializing an event. It should also be called when using asynchronous or
* deferred logging.
* <p/>
* <p/>
* Note that due to performance concerns, this method does NOT extract caller
* data. It is the responsibility of the caller to extract caller information.
* Note that due to performance concerns, this method does NOT extract caller data. It is the responsibility of the
* caller to extract caller information.
*/
public void prepareForDeferredProcessing() {
this.getFormattedMessage();
Expand Down Expand Up @@ -280,7 +326,7 @@ public void setMessage(String message) {

/**
* Return the {@link Instant} corresponding to the creation of this event.
*
*
* @see {@link #getTimeStamp()}
* @since 1.3
*/
Expand All @@ -290,7 +336,7 @@ public Instant getInstant() {

/**
* Set {@link Instant} corresponding to the creation of this event.
*
*
* The value of {@link #getTimeStamp()} will be overridden as well.
*/
public void setInstant(Instant instant) {
Expand All @@ -304,9 +350,9 @@ public long getTimeStamp() {
return timeStamp;
}


/**
* Return the number of nanoseconds past the {@link #getTimeStamp() timestamp in seconds}.
*
* @since 1.3.0
*/
@Override
Expand All @@ -316,11 +362,9 @@ public int getNanoseconds() {

/**
* Set the number of elapsed milliseconds since epoch in UTC.
*
* Setting the timestamp will override the value contained in
* {@link #getInstant}. Nanoseconds value will be computed form the provided
* millisecond value.
*
*
* Setting the timestamp will override the value contained in {@link #getInstant}. Nanoseconds value will be
* computed form the provided millisecond value.
*/
public void setTimeStamp(long timeStamp) {
Instant instant = Instant.ofEpochMilli(timeStamp);
Expand All @@ -344,13 +388,11 @@ public void setLevel(Level level) {
}

/**
* Get the caller information for this logging event. If caller information is
* null at the time of its invocation, this method extracts location
* information. The collected information is cached for future use.
* Get the caller information for this logging event. If caller information is null at the time of its invocation,
* this method extracts location information. The collected information is cached for future use.
* <p/>
* <p>
* Note that after serialization it is impossible to correctly extract caller
* information.
* Note that after serialization it is impossible to correctly extract caller information.
* </p>
*/
public StackTraceElement[] getCallerData() {
Expand Down Expand Up @@ -450,9 +492,8 @@ public String toString() {
}

/**
* LoggerEventVO instances should be used for serialization. Use
* {@link LoggingEventVO#build(ILoggingEvent) build} method to create the
* LoggerEventVO instance.
* LoggerEventVO instances should be used for serialization. Use {@link LoggingEventVO#build(ILoggingEvent) build}
* method to create the LoggerEventVO instance.
*
* @since 1.0.11
*/
Expand Down

0 comments on commit 5a36133

Please sign in to comment.