CentralLogRecord.java
/*
** Module : CentralLogRecord.java
** Abstract : Central Log Record
**
** Copyright (c) 2023-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------------------Description-----------------------------
** 001 GBB 20230207 Initial setup
** 002 GBB 20230613 convertToLevel moved to LoggingUtils.
** TJD 20240123 Java 17 compatibility updates
** 003 GBB 20240729 Create ContextLogRecord with LogContext.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util.logging;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import static com.goldencode.util.NativeTypeSerializer.*;
/**
* An alternative to {@link LogRecord} that implements the {@link Externalizable} interface. Used to
* transfer log records between the client and the server.
*/
public class CentralLogRecord
implements Externalizable
{
/** Process ID. */
private long pid;
/** OS user ID. */
private String userOS;
/** The level of the log msg. */
private Level level;
/** The class where the msg originates from. */
private String sourceClassName;
/** The method where the msg originates from. */
private String sourceMethodName;
/** The log message. */
private String message;
/** The event time in milliseconds since 1970. */
private long millis = new Date().getTime();
/** The Throwable associated with log message. */
private Throwable thrown;
/** The name of the logger. */
private String loggerName;
/** The format parameters. */
private Object[] parameters;
/** The thread name. */
private String threadName;
/** The FWD account. */
private String fwdUser;
/** The session ID. */
private String sessionId;
/** The thread id. */
private Integer threadId;
/**
* Converts a standard java {@link ContextLogRecord} to {@link CentralLogRecord}.
*
* @param logRecord
* A log record.
* @param pid
* A process ID.
* @param userOS
* OS user ID.
*
* @return The log record converted to CentralLogRecord.
*/
public static CentralLogRecord from(ContextLogRecord logRecord, long pid, String userOS)
{
CentralLogRecord clr = new CentralLogRecord();
clr.pid = pid;
clr.userOS = userOS;
clr.level = logRecord.getLevel();
clr.sourceClassName = logRecord.getSourceClassName();
clr.sourceMethodName = logRecord.getSourceMethodName();
clr.millis = logRecord.getMillis();
clr.loggerName = logRecord.getLoggerName();
clr.message = logRecord.getMessage();
clr.parameters = logRecord.getParameters();
clr.thrown = logRecord.getThrown();
clr.threadName = Thread.currentThread().getName();
clr.threadId = logRecord.getThreadID();
ContextLogRecord.LogContext logContext = logRecord.getLogContext();
if (logContext != null)
{
clr.fwdUser = logContext.getFwdUser();
clr.sessionId = logContext.getSessionId();
}
return clr;
}
/**
* Writes the fields of this object to the out stream in a format supported by Externalizable. Uses
* helper methods from {@link com.goldencode.util.NativeTypeSerializer}.
*
* @param out
* The stream to write the object to.
*
* @throws IOException Any I/O exceptions that may occur
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException
{
writeLong(out, pid);
writeString(out, userOS);
writeInteger(out, level == null ? -1 : level.intValue());
writeString(out, sourceClassName);
writeString(out, sourceMethodName);
if (parameters != null && parameters.length > 0)
{
// Params can be of any type, not Externalizable, so format the msg
try
{
message = String.format(message, parameters);
}
catch (Throwable ignore)
{
}
parameters = null;
}
if (thrown != null)
{
// Throwable is not Externalizable, so concat to msg
StringBuilder sb = new StringBuilder(message);
sb.append(" ");
CentralLogFormatter.dumpThrowable(sb, thrown);
message = sb.toString();
}
writeString(out, message);
writeLong(out, millis);
writeString(out, loggerName);
writeString(out, threadName);
writeInteger(out, threadId);
writeString(out, fwdUser);
writeString(out, sessionId);
}
/**
* Restores the contents of this object from the input stream from a format supported by Externalizable.
* Uses helper methods from {@link com.goldencode.util.NativeTypeSerializer}.
*
* @param in
* The stream to read data from.
*
* @throws IOException Any I/O exceptions that may occur
* @throws ClassNotFoundException The class for an object being restored cannot be found.
*/
@Override
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
pid = readLong(in);
userOS = readString(in);
level = LoggingUtil.convertToLevel(readInteger(in)).orElse(null);
sourceClassName = readString(in);
sourceMethodName = readString(in);
message = readString(in);
millis = readLong(in);
loggerName = readString(in);
threadName = readString(in);
threadId = readInteger(in);
fwdUser = readString(in);
sessionId = readString(in);
}
/**
* Returns this object converted to {@link LogRecord}.
*
* @return This object converted to LogRecord.
*/
@SuppressWarnings("deprecation")
public ContextLogRecord toLogRecord()
{
if (this.level == null)
{
// preventing NPE, no log level is not expected though
this.level = Level.INFO;
}
ContextLogRecord cl = new ContextLogRecord(this.level, this.message);
cl.setSourceClassName(this.sourceClassName);
cl.setSourceMethodName(this.sourceMethodName);
// LogRecord.setInstant is not available in JDK 1.8
// In JDK 9+ cl.setMillis should be replaced with:
// cl.setInstant(Instant.ofEpochMilli(this.millis));
// next line has to stay for compatibility with JDK 1.8
cl.setMillis(this.millis);
cl.setLoggerName(this.loggerName);
cl.setParameters(this.parameters);
cl.setThrown(this.thrown);
if (this.threadId != null)
{
cl.setThreadID(this.threadId);
}
ContextLogRecord.LogContext logContext = new ContextLogRecord.LogContext();
logContext.setFwdUser(fwdUser);
logContext.setSessionId(sessionId);
logContext.setThreadName(threadName);
logContext.setPid(pid);
logContext.setThreadId(LoggingUtil.addLeadingZeros(threadId, 8));
cl.setLogContext(logContext);
return cl;
}
/**
* Getter for the process ID.
*
* @return The process ID.
*/
public long getPid()
{
return pid;
}
/**
* Getter for the process OS user ID.
*
* @return The process OS user ID.
*/
public String getUserOS()
{
return userOS;
}
/**
* Getter for the log level.
*
* @return The log level.
*/
public Level getLevel()
{
return level;
}
/**
* Setter for the log level.
*
* @param level
* The log level.
*/
public void setLevel(Level level)
{
this.level = level;
}
/**
* Getter for the source class name.
*
* @return The source class name.
*/
public String getSourceClassName()
{
return sourceClassName;
}
/**
* Setter for the source class name.
*
* @param sourceClassName
* The source class name.
*/
public void setSourceClassName(String sourceClassName)
{
this.sourceClassName = sourceClassName;
}
/**
* Getter for the source method name.
*
* @return The source method name.
*/
public String getSourceMethodName()
{
return sourceMethodName;
}
/**
* Setter for the source method name.
*
* @param sourceMethodName
* The source method name.
*/
public void setSourceMethodName(String sourceMethodName)
{
this.sourceMethodName = sourceMethodName;
}
/**
* Getter for the message.
*
* @return The message.
*/
public String getMessage()
{
return message;
}
/**
* Setter for the message.
*
* @param message
* The message.
*/
public void setMessage(String message)
{
this.message = message;
}
/**
* Getter for the millis.
*
* @return The millis.
*/
public long getMillis()
{
return millis;
}
/**
* Setter for the millis.
*
* @param millis
* The millis.
*/
public void setMillis(long millis)
{
this.millis = millis;
}
/**
* Getter for the Throwable.
*
* @return The Throwable.
*/
public Throwable getThrown()
{
return thrown;
}
/**
* Setter for the Throwable.
*
* @param thrown
* The Throwable.
*/
public void setThrown(Throwable thrown)
{
this.thrown = thrown;
}
/**
* Getter for the logger name.
*
* @return The logger name.
*/
public String getLoggerName()
{
return loggerName;
}
/**
* Setter for the logger name.
*
* @param loggerName
* The logger name.
*/
public void setLoggerName(String loggerName)
{
this.loggerName = loggerName;
}
/**
* Getter for the parameters.
*
* @return The parameters.
*/
public Object[] getParameters()
{
return parameters;
}
/**
* Setter for the parameters.
*
* @param parameters
* The parameters.
*/
public void setParameters(Object... parameters)
{
this.parameters = parameters;
}
/**
* Getter for the thread id.
*
* @return The thread id.
*/
public Integer getThreadId()
{
return threadId;
}
/**
* Getter for the thread name.
*
* @return The thread name.
*/
public String getThreadName()
{
return threadName;
}
/**
* Getter for the FWD account.
*
* @return The FWD account.
*/
public String getFwdUser()
{
return fwdUser;
}
/**
* Getter for the session ID.
*
* @return The session ID.
*/
public String getSessionId()
{
return sessionId;
}
}