blob: 3d186782c5874e8f31208f6fac21af1b9559223e [file] [log] [blame]
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// tware - initial
package org.eclipse.persistence.jpa.rs.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.logging.Level;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.persistence.internal.jpa.rs.weaving.PersistenceWeavedRest;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.jpa.rs.DataStorage;
import org.eclipse.persistence.jpa.rs.PersistenceContext;
import org.eclipse.persistence.jpa.rs.logging.LoggingLocalization;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.logging.SessionLogEntry;
import org.eclipse.persistence.sessions.Session;
/**
* Logger for EclipseLink JPA-RS related functionality.
* Publishes messages under the {@link SessionLog#JPARS} category.
*/
public class JPARSLogger {
private static final SessionLog defaultLog = AbstractSessionLog.getLog();
/**
* Entering
*
* @param sourceClass the source class
* @param sourceMethod the source method
* @param params parameters
*/
public static void entering(String sourceClass, String sourceMethod, Object[] params) {
entering(defaultLog, sourceClass, sourceMethod, params);
}
/**
* Entering
*
* @param sessionLog the log
* @param sourceClass the source class
* @param sourceMethod the source method
* @param params parameters
*/
public static void entering(SessionLog sessionLog, String sourceClass, String sourceMethod, Object[] params) {
// Logger logs entering logs when log level <= FINER. But, we want to get these logs created only when the log level is FINEST.
if (isLoggableFinest(sessionLog)) {
SessionLogEntry sle = newLogEntry(sessionLog.getSession());
sle.setSourceClassName(sourceClass);
sle.setSourceMethodName(sourceMethod);
sle.setMessage("ENTRY {0}");
sle.setParameters(getParamsWithAdditionalInfo(params));
sessionLog.log(sle);
}
}
/**
* Entering
*
* @param sourceClass the source class
* @param sourceMethod the source method
* @param in the input stream
*/
public static void entering(String sourceClass, String sourceMethod, InputStream in) {
entering(defaultLog, sourceClass, sourceMethod, in);
}
/**
* Entering
*
* @param sessionLog log receiving the message
* @param sourceClass the source class
* @param sourceMethod the source method
* @param in the input stream
*/
public static void entering(SessionLog sessionLog, String sourceClass, String sourceMethod, InputStream in) {
// Logger logs entering logs when log level <= FINER. But, we want to get these logs created only when the log level is FINEST.
// make sure input stream supports mark so that the or create a new BufferedInputStream which supports mark.
// when mark is supported, the stream remembers all the bytes read after the call to mark and
// stands ready to supply those same bytes again if and whenever the method reset is called.
if (isLoggableFinest(sessionLog) && (in.markSupported())) {
try {
String data = readData(in);
in.reset();
if (data != null) {
SessionLogEntry sle = newLogEntry(sessionLog.getSession());
sle.setSourceClassName(sourceClass);
sle.setSourceMethodName(sourceMethod);
sle.setMessage("ENTRY {0}");
sle.setParameters(getParamsWithAdditionalInfo(new Object[] { data }));
sessionLog.log(sle);
}
} catch (Throwable throwable) {
exception(throwable.getMessage(), new Object[] {}, throwable);
}
}
}
/**
* Exiting
*
* @param sourceClass the source class
* @param sourceMethod the source method
* @param params parameters
*/
public static void exiting(String sourceClass, String sourceMethod, Object[] params) {
exiting(defaultLog, sourceClass, sourceMethod, params);
}
/**
* Exiting
*
* @param sessionLog the log
* @param sourceClass the source class
* @param sourceMethod the source method
* @param params parameters
*/
public static void exiting(SessionLog sessionLog, String sourceClass, String sourceMethod, Object[] params) {
// Logger logs exiting logs when log level <= FINER. But, we want to get these logs created only when the log level is FINEST.
if (isLoggableFinest()) {
try {
SessionLogEntry sle = newLogEntry(sessionLog.getSession());
sle.setSourceClassName(sourceClass);
sle.setSourceMethodName(sourceMethod);
sle.setMessage("RETURN {0}");
sle.setParameters(new Object[] {new MethodExitLogData(getParamsWithAdditionalInfo(params))});
sessionLog.log(sle);
} catch (Throwable throwable) {
exception(throwable.getMessage(), new Object[] {}, throwable);
}
}
}
/**
* Exiting
*
* @param sourceClass the source class
* @param sourceMethod the source method
* @param context the context
* @param object the object
* @param mediaType the media type
*/
public static void exiting(String sourceClass, String sourceMethod, PersistenceContext context, Object object, MediaType mediaType) {
exiting(defaultLog, sourceClass, sourceMethod, context, object, mediaType);
}
/**
* Exiting
*
* @param sessionLog the log
* @param sourceClass the source class
* @param sourceMethod the source method
* @param context the context
* @param object the object
* @param mediaType the media type
*/
public static void exiting(SessionLog sessionLog, String sourceClass, String sourceMethod, PersistenceContext context, Object object, MediaType mediaType) {
// Log marshaled object only when the log level is FINEST
if (isLoggableFinest(sessionLog) && (context != null) && (object != null) && (mediaType != null)) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
context.marshall(object, mediaType, outputStream, true);
if (object instanceof PersistenceWeavedRest) {
exiting(sessionLog, sourceClass, sourceMethod, new Object[] { object.getClass().getName(), outputStream.toString(StandardCharsets.UTF_8.name())});
} else {
exiting(sessionLog, sourceClass, sourceMethod, new Object[] { outputStream.toString(StandardCharsets.UTF_8.name()) });
}
} catch (Throwable throwable) {
exception(throwable.getMessage(), new Object[] {}, throwable);
}
}
}
/**
* Finest
*
* @param message the message
* @param params parameters
*/
public static void finest(String message, Object[] params) {
finest(defaultLog, message, params);
}
/**
* Finest
*
* @param sessionLog the log
* @param message the message
* @param params parameters
*/
public static void finest(SessionLog sessionLog, String message, Object[] params) {
log(sessionLog, SessionLog.FINEST, message, getParamsWithAdditionalInfo(params));
}
/**
* Fine
*
* @param message the message
* @param params parameters
*/
public static void fine(String message, Object[] params) {
fine(defaultLog, message, params);
}
/**
* Fine
*
* @param sessionLog the log
* @param message the message
* @param params parameters
*/
public static void fine(SessionLog sessionLog, String message, Object[] params) {
log(sessionLog, SessionLog.FINE, message, getParamsWithAdditionalInfo(params));
}
/**
* Warning
*
* @param message the message
* @param params parameters
*/
public static void warning(String message, Object[] params) {
warning(defaultLog, message, params);
}
/**
* Warning
*
* @param sessionLog the log
* @param message the message
* @param params parameters
*/
public static void warning(SessionLog sessionLog, String message, Object[] params) {
log(sessionLog, SessionLog.WARNING, message, getParamsWithAdditionalInfo(params));
}
/**
* Error
*
* @param message the message
* @param params parameters
*/
public static void error(String message, Object[] params) {
error(defaultLog, message, params);
}
/**
* Error
*
* @param sessionLog the log
* @param message the message
* @param params parameters
*/
public static void error(SessionLog sessionLog, String message, Object[] params) {
log(sessionLog, SessionLog.SEVERE, message, getParamsWithAdditionalInfo(params));
}
/**
* Exception
*
* @param message the message
* @param params parameters
* @param exc the throwable
*/
public static void exception(String message, Object[] params, Throwable exc) {
exception(defaultLog, message, params, exc);
}
/**
* Exception
*
* @param sessionLog the log
* @param message the message
* @param params parameters
* @param exc the throwable
*/
public static void exception(SessionLog sessionLog, String message, Object[] params, Throwable exc) {
log(sessionLog, SessionLog.SEVERE, message, getParamsWithAdditionalInfo(params), exc);
}
/**
* Sets the log level
*
* @param level the new log level
*/
public static void setLogLevel(Level level) {
setLogLevel(defaultLog, AbstractSessionLog.translateStringToLoggingLevel(level.getName()));
}
/**
* Sets the log level
*
* @param sessionLog the log
* @param level the new log level
*/
public static void setLogLevel(SessionLog sessionLog, int level) {
sessionLog.setLevel(level, SessionLog.JPARS);
}
/**
* @return true if log level is set to {@link SessionLog#FINEST}
*/
public static boolean isLoggableFinest() {
return isLoggableFinest(defaultLog);
}
/**
* @param sessionLog the log
*
* @return true if log level is set to {@link SessionLog#FINEST}
*/
public static boolean isLoggableFinest(SessionLog sessionLog) {
return sessionLog.shouldLog(SessionLog.FINEST, SessionLog.JPARS);
}
private static Object[] getParamsWithAdditionalInfo(Object[] params) {
String requestId = (String) DataStorage.get(DataStorage.REQUEST_ID);
if (params != null) {
Object[] paramsWithRequestId = new Object[params.length + 1];
paramsWithRequestId[0] = requestId;
System.arraycopy(params, 0, paramsWithRequestId, 1, params.length);
return paramsWithRequestId;
}
return new Object[] { requestId };
}
private static void log(SessionLog sessionLog, int level, String message, Object[] params) {
log(sessionLog, level, message, params, null);
}
private static void log(SessionLog sessionLog, int level, String message, Object[] params, Throwable t) {
Objects.requireNonNull(sessionLog);
if (sessionLog.shouldLog(level, SessionLog.JPARS)) {
SessionLogEntry sle = newLogEntry(sessionLog.getSession());
sle.setLevel(level);
sle.setMessage(LoggingLocalization.buildMessage(message, params));
sle.setParameters(params);
sle.setException(t);
sessionLog.log(sle);
}
}
private static SessionLogEntry newLogEntry(Session session) {
SessionLogEntry entry = session instanceof AbstractSession
? new SessionLogEntry((AbstractSession) session)
: new SessionLogEntry(null);
entry.setLevel(SessionLog.FINEST);
entry.setNameSpace(SessionLog.JPARS);
entry.setShouldTranslate(false);
return entry;
}
private static String readData(InputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ByteArrayInputStream bais = null;
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] bytes = buffer.toByteArray();
bais = new ByteArrayInputStream(bytes);
return getDataFromInputStream(bais);
}
private static String getDataFromInputStream(InputStream is) {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
// ignore
}
return sb.toString();
}
}