wolfcrypt-jni/src/main/java/com/wolfssl/provider/jce/WolfCryptDebug.java

208 lines
6.4 KiB
Java

/* WolfCryptDebug.java
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl.provider.jce;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.function.Supplier;
class WolfCryptDebug {
private static final Logger jceLogger =
Logger.getLogger("com.wolfssl.provider.jce");
public static boolean DEBUG = checkProperty();
/** Error level debug message */
public static final String ERROR = "ERROR";
/** Info level debug message */
public static final String INFO = "INFO";
/** Time formatter for log messages */
private static final DateTimeFormatter TimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
.withZone(ZoneId.systemDefault());
static {
configureLoggers();
}
/**
* Custom handler that flushes after each log record
*/
private static class FlushingStreamHandler extends StreamHandler {
public FlushingStreamHandler() {
super(System.err, new WolfCryptFormatter());
}
@Override
public synchronized void publish(LogRecord record) {
super.publish(record);
flush();
}
}
/**
* Configure loggers based on system properties
*/
private static void configureLoggers() {
/* Remove any existing handlers */
for (Handler handler : jceLogger.getHandlers()) {
jceLogger.removeHandler(handler);
}
/* Only configure handlers if debug is enabled */
if (DEBUG) {
/* Create custom handler that flushes after each log record */
FlushingStreamHandler handler = new FlushingStreamHandler();
handler.setFormatter(new WolfCryptFormatter());
jceLogger.addHandler(handler);
}
/* Set log levels based on debug properties */
jceLogger.setLevel(DEBUG ? Level.ALL : Level.OFF);
/* Disable parent handlers to prevent double logging */
jceLogger.setUseParentHandlers(false);
}
/**
* Custom formatter for log records
*/
private static class WolfCryptFormatter extends Formatter {
@Override
public String format(LogRecord record) {
if (record == null) {
return "null record\n";
}
String sourceClass = record.getSourceClassName();
if (sourceClass == null) {
sourceClass = "";
} else {
/* Extract simple class name (after last dot) */
int lastDot = sourceClass.lastIndexOf('.');
if (lastDot != -1) {
sourceClass = sourceClass.substring(lastDot + 1);
}
}
Level level = record.getLevel();
String levelStr = level != null ? level.getName() : "UNKNOWN";
@SuppressWarnings("deprecation")
long threadId = record.getThreadID();
String message = record.getMessage();
if (message == null) {
message = "";
}
else {
/* Escape CR and LF */
message = message.replace("\r", "\\r").replace("\n", "\\n");
}
return String.format("%s [%s %s: TID %d: %s] %s\n",
TimeFormatter.format(
Instant.ofEpochMilli(record.getMillis())),
"wolfJCE",
levelStr,
threadId,
sourceClass,
message);
}
}
private static boolean checkProperty() {
String enabled = System.getProperty("wolfjce.debug");
if ((enabled != null) && (enabled.equalsIgnoreCase("true"))) {
return true;
}
return false;
}
/**
* Refresh debug enabled/disabled flags based on current
* System properties.
*/
public static synchronized void refreshDebugFlags() {
boolean oldDebug = DEBUG;
DEBUG = checkProperty();
/* Only reconfigure if debug state has changed */
if (oldDebug != DEBUG) {
configureLoggers();
}
}
/**
* Print out debug message if debugging is enabled.
*
* @param <T> class type of cl
* @param cl class being called from to get debug info
* @param tag level of debug message, ie WolfCryptDebug.INFO
* @param messageSupplier supplier of message to be printed out
*/
public static synchronized <T> void log(Class<T> cl, String tag,
Supplier<String> messageSupplier) {
log(cl, "wolfJCE", tag, 0, messageSupplier);
}
/**
* Print out debug message if debugging is enabled.
*
* @param <T> class type of cl
* @param cl class being called from to get debug info
* @param component component name, ie "wolfJCE"
* @param tag level of debug message, ie WolfCryptDebug.INFO
* @param nativePtr native pointer
* @param messageSupplier supplier of message to be printed out
*/
public static synchronized <T> void log(Class<T> cl, String component,
String tag, long nativePtr, Supplier<String> messageSupplier) {
if (!DEBUG) {
return;
}
Level level = tag.equals(ERROR) ? Level.SEVERE : Level.INFO;
String msg = messageSupplier.get();
if (nativePtr != 0) {
msg = msg + " [nativePtr=" + nativePtr + "]";
}
LogRecord record = new LogRecord(level, msg);
record.setSourceClassName(cl.getName());
jceLogger.log(record);
}
}