This commit is contained in:
candi
2025-09-04 04:43:31 +08:00
parent 2723b0ddd3
commit 212c19d40a
136 changed files with 96 additions and 766 deletions

View File

@@ -0,0 +1,278 @@
/*******************************************************************************
* Copyright (c) 2009, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0
* and the Eclipse Distribution License is available at
* https://www.eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Dave Locke - initial API and implementation and/or initial documentation
*/
package org.eclipse.paho.mqttv5.client.logging;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.MemoryHandler;
/**
* Implementation of the the logger interface that uses java.uti.logging
*
* A Logger that utilises Java's built in logging facility - java.util.logging.
* <p>A sample java.util.logging properties file - jsr47min.properties is provided that demonstrates
* how to run with a memory based trace facility that runs with minimal performance
* overhead. The memory buffer can be dumped when a log/trace record is written matching
* the MemoryHandlers trigger level or when the push method is invoked on the MemoryHandler.
* {@link org.eclipse.paho.mqttv5.client.util.Debug Debug} provides method to make it easy
* to dump the memory buffer as well as other useful debug info.
*/
public class JSR47Logger implements Logger {
private java.util.logging.Logger julLogger = null;
private ResourceBundle logMessageCatalog = null;
private ResourceBundle traceMessageCatalog = null;
private String catalogID = null;
private String resourceName = null;
private String loggerName = null;
/**
*
* @param logMsgCatalog The resource bundle associated with this logger
* @param loggerID The suffix for the loggerName (will be appeneded to org.eclipse.paho.mqttv5.client
* @param resourceContext A context for the logger e.g. clientID or appName...
*/
public void initialise(ResourceBundle logMsgCatalog, String loggerID, String resourceContext ) {
this.traceMessageCatalog = logMessageCatalog;
this.resourceName = resourceContext;
// loggerName = "org.eclipse.paho.mqttv5.client." + ((null == loggerID || 0 == loggerID.length()) ? "internal" : loggerID);
loggerName = loggerID;
this.julLogger = java.util.logging.Logger.getLogger(loggerName);
this.logMessageCatalog = logMsgCatalog;
this.traceMessageCatalog = logMsgCatalog;
this.catalogID = logMessageCatalog.getString("0");
}
public void setResourceName(String logContext) {
this.resourceName = logContext;
}
public boolean isLoggable(int level) {
return julLogger.isLoggable(mapJULLevel(level)); // || InternalTracer.isLoggable(level);
}
public void severe(String sourceClass, String sourceMethod, String msg) {
log(SEVERE, sourceClass, sourceMethod, msg, null, null);
}
public void severe(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
log(SEVERE, sourceClass, sourceMethod, msg, inserts, null);
}
public void severe(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown) {
log(SEVERE, sourceClass, sourceMethod, msg, inserts, thrown);
}
public void warning(String sourceClass, String sourceMethod, String msg) {
log(WARNING, sourceClass, sourceMethod, msg, null, null);
}
public void warning(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
log(WARNING, sourceClass, sourceMethod, msg, inserts, null);
}
public void warning(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown) {
log(WARNING, sourceClass, sourceMethod, msg, inserts, thrown);
}
public void info(String sourceClass, String sourceMethod, String msg) {
log(INFO, sourceClass, sourceMethod, msg, null, null);
}
public void info(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
log(INFO, sourceClass, sourceMethod, msg, inserts, null);
}
public void info(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown) {
log(INFO, sourceClass, sourceMethod, msg, inserts, thrown);
}
public void config(String sourceClass, String sourceMethod, String msg) {
log(CONFIG, sourceClass, sourceMethod, msg, null, null);
}
public void config(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
log(CONFIG, sourceClass, sourceMethod, msg, inserts, null);
}
public void config(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown) {
log(CONFIG, sourceClass, sourceMethod, msg, inserts, thrown);
}
public void log(int level, String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown) {
// InternalTracer.log(this.catalogID, level, sourceClass, sourceMethod, msg, inserts, thrown);
java.util.logging.Level julLevel = mapJULLevel(level);
if (julLogger.isLoggable(julLevel)) {
logToJsr47(julLevel, sourceClass, sourceMethod, this.catalogID, this.logMessageCatalog, msg, inserts, thrown);
}
}
// public void setTrace(Trace trace) {
// InternalTracer.setTrace(trace);
// }
public void fine(String sourceClass, String sourceMethod, String msg) {
trace(FINE, sourceClass, sourceMethod, msg, null, null);
}
public void fine(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
trace(FINE, sourceClass, sourceMethod, msg, inserts, null);
}
public void fine(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex) {
trace(FINE, sourceClass, sourceMethod, msg, inserts, ex);
}
public void finer(String sourceClass, String sourceMethod, String msg) {
trace(FINER, sourceClass, sourceMethod, msg, null, null);
}
public void finer(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
trace(FINER, sourceClass, sourceMethod, msg, inserts, null);
}
public void finer(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex) {
trace(FINER, sourceClass, sourceMethod, msg, inserts, ex);
}
public void finest(String sourceClass, String sourceMethod, String msg) {
trace(FINEST, sourceClass, sourceMethod, msg, null, null);
}
public void finest(String sourceClass, String sourceMethod, String msg, Object[] inserts) {
trace(FINEST, sourceClass, sourceMethod, msg, inserts, null);
}
public void finest(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex) {
trace(FINEST, sourceClass, sourceMethod, msg, inserts, ex);
}
public void trace(int level, String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex) {
java.util.logging.Level julLevel = mapJULLevel(level);
boolean isJULLoggable = julLogger.isLoggable(julLevel);
// if (FINE == level || isJULLoggable || InternalTracer.isLoggable(level)) {
// InternalTracer.traceForced(level, sourceClass, sourceMethod, msg, inserts);
// }
if (isJULLoggable) {
logToJsr47(julLevel, sourceClass, sourceMethod, this.catalogID, this.traceMessageCatalog, msg, inserts, ex);
}
}
private String getResourceMessage(ResourceBundle messageCatalog, String msg) {
String message;
try {
message = messageCatalog.getString(msg);
} catch (MissingResourceException e) {
// This is acceptable, simply return the given msg string.
message = msg;
}
return message;
}
private void logToJsr47(java.util.logging.Level julLevel, String sourceClass, String sourceMethod, String catalogName,
ResourceBundle messageCatalog, String msg, Object[] inserts, Throwable thrown) {
// LogRecord logRecord = new LogRecord(julLevel, msg);
String formattedWithArgs = msg;
if (!msg.contains("=====")) {
formattedWithArgs = MessageFormat.format(getResourceMessage(messageCatalog, msg), inserts);
}
LogRecord logRecord = new LogRecord(julLevel, resourceName + ": " +formattedWithArgs);
logRecord.setSourceClassName(sourceClass);
logRecord.setSourceMethodName(sourceMethod);
logRecord.setLoggerName(loggerName);
// logRecord.setResourceBundleName(catalogName);
// logRecord.setResourceBundle(messageCatalog);
// if (null != inserts) {
// logRecord.setParameters(inserts);
// }
if (null != thrown) {
logRecord.setThrown(thrown);
}
julLogger.log(logRecord);
}
private java.util.logging.Level mapJULLevel(int level) {
java.util.logging.Level julLevel = null;
switch (level) {
case SEVERE:
julLevel = java.util.logging.Level.SEVERE;
break;
case WARNING:
julLevel = java.util.logging.Level.WARNING;
break;
case INFO:
julLevel = java.util.logging.Level.INFO;
break;
case CONFIG:
julLevel = java.util.logging.Level.CONFIG;
break;
case FINE:
julLevel = java.util.logging.Level.FINE;
break;
case FINER:
julLevel = java.util.logging.Level.FINER;
break;
case FINEST:
julLevel = java.util.logging.Level.FINEST;
break;
default:
}
return julLevel;
}
public String formatMessage(String msg, Object[] inserts) {
String formatString;
try {
formatString = logMessageCatalog.getString(msg);
} catch (MissingResourceException e) {
formatString = msg;
}
return formatString;
}
public void dumpTrace() {
dumpMemoryTrace47(julLogger);
}
protected static void dumpMemoryTrace47(java.util.logging.Logger logger) {
MemoryHandler mHand = null;
if (logger!= null) {
Handler[] handlers = logger.getHandlers();
for (Handler handler : handlers) {
if (handler instanceof MemoryHandler) {
synchronized (handler) {
mHand = ((MemoryHandler) handler);
mHand.push();
return;
} // synchronized (handler).
}
} // for handlers...
dumpMemoryTrace47(logger.getParent());
}
}
}

View File

@@ -0,0 +1,579 @@
/*******************************************************************************
* Copyright (c) 2009, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0
* and the Eclipse Distribution License is available at
* https://www.eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Dave Locke - initial API and implementation and/or initial documentation
*/
package org.eclipse.paho.mqttv5.client.logging;
import java.util.ResourceBundle;
/**
* A Logger object is used to send log and trace messages to a platform
* specific logging implementation. Loggers are named, using a hierarchical
* dot-separated name-space.
* Logger names can be arbitrary strings, but they should normally be based on
* the component or the package name of the logged component
*
* Logger objects may be obtained by calls on one of the getLogger factory
* methods. These will either create a new Logger or return a suitable existing
* Logger.
*
* <p>
* The int levels define a set of standard logging levels that can be used to
* control logging output. The logging levels are ordered and are specified by
* ordered integers. Enabling logging at a given level also enables logging at
* all higher levels.
* <p>
* Clients should use the the convenience methods such as severe() and fine() or
* one of the predefined level constants such as Logger.SEVERE and Logger.FINE
* with the appropriate log(int level...) or trace(int level...) methods.
* <p>
* The levels in descending order are:</p>
* <ul>
* <li>SEVERE (log - highest value)</li>
* <li>WARNING (log)</li>
* <li>INFO (log)</li>
* <li>CONFIG (log)</li>
* <li>FINE (trace)</li>
* <li>FINER (trace)</li>
* <li>FINEST (trace - lowest value)</li>
* </ul>
*
*/
public interface Logger {
/**
* SEVERE is a message level indicating a serious failure.
* <p>
* In general SEVERE messages should describe events that are of
* considerable importance and which will prevent normal program execution.
* They should be reasonably intelligible to end users and to system
* administrators.
*/
int SEVERE = 1;
/**
* WARNING is a message level indicating a potential problem.
* <p>
* In general WARNING messages should describe events that will be of
* interest to end users or system managers, or which indicate potential
* problems.
*/
int WARNING = 2;
/**
* INFO is a message level for informational messages.
* <p>
* Typically INFO messages will be written to the console or its equivalent.
* So the INFO level should only be used for reasonably significant messages
* that will make sense to end users and system admins.
*/
int INFO = 3;
/**
* CONFIG is a message level for static configuration messages.
* <p>
* CONFIG messages are intended to provide a variety of static configuration
* information, to assist in debugging problems that may be associated with
* particular configurations. For example, CONFIG message might include the
* CPU type, the graphics depth, the GUI look-and-feel, etc.
*/
int CONFIG = 4;
/**
* FINE is a message level providing tracing information.
* <p>
* All of FINE, FINER, and FINEST are intended for relatively detailed
* tracing. The exact meaning of the three levels will vary between
* subsystems, but in general, FINEST should be used for the most voluminous
* detailed output, FINER for somewhat less detailed output, and FINE for
* the lowest volume (and most important) messages.
* <p>
* In general the FINE level should be used for information that will be
* broadly interesting to developers who do not have a specialized interest
* in the specific subsystem.
* <p>
* FINE messages might include things like minor (recoverable) failures.
* Issues indicating potential performance problems are also worth logging
* as FINE.
*/
int FINE = 5;
/**
* FINER indicates a fairly detailed tracing message. By default logging
* calls for entering, returning, or throwing an exception are traced at
* this level.
*/
int FINER = 6;
/**
* FINEST indicates a highly detailed tracing message.
*/
int FINEST = 7;
void initialise(ResourceBundle messageCatalog, String loggerID, String resourceName);
/**
* Set a name that can be used to provide context with each log record.
* This overrides the value passed in on initialise
* @param logContext The Log context name
*/
void setResourceName(String logContext);
/**
* Check if a message of the given level would actually be logged by this
* logger. This check is based on the Loggers effective level, which may be
* inherited from its parent.
*
* @param level
* a message logging level.
* @return true if the given message level is currently being logged.
*/
boolean isLoggable(int level);
/**
* Log a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used.
*/
void severe(String sourceClass, String sourceMethod, String msg);
/**
* Log a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void severe(String sourceClass, String sourceMethod, String msg, Object[] inserts);
/**
* Log a message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
* @param thrown
* Throwable associated with log message.
*/
void severe(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown);
/**
* Log a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used.
*/
void warning(String sourceClass, String sourceMethod, String msg);
/**
* Log a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void warning(String sourceClass, String sourceMethod, String msg, Object[] inserts);
/**
* Log a message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
* @param thrown
* Throwable associated with log message.
*/
void warning(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown);
/**
* Log a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used.
*/
void info(String sourceClass, String sourceMethod, String msg);
/**
* Log a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void info(String sourceClass, String sourceMethod, String msg, Object[] inserts);
/**
* Log a message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
* @param thrown
* Throwable associated with log message.
*/
void info(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown);
/**
* Log a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used.
*/
void config(String sourceClass, String sourceMethod, String msg);
/**
* Log a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void config(String sourceClass, String sourceMethod, String msg, Object[] inserts);
/**
* Log a message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
* @param thrown
* Throwable associated with log message.
*/
void config(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown);
/**
* Trace a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used.
*/
void fine(String sourceClass, String sourceMethod, String msg);
/**
* Trace a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used. The
* formatter uses java.text.MessageFormat style formatting to
* format parameters, so for example a format string "{0} {1}"
* would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void fine(String sourceClass, String sourceMethod, String msg, Object[] inserts);
void fine(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex);
/**
* Trace a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used.
*/
void finer(String sourceClass, String sourceMethod, String msg);
/**
* Trace a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used. The
* formatter uses java.text.MessageFormat style formatting to
* format parameters, so for example a format string "{0} {1}"
* would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void finer(String sourceClass, String sourceMethod, String msg, Object[] inserts);
void finer(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex);
/**
* Trace a message, specifying source class and method, if the logger is
* currently enabled for the given message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used.
*/
void finest(String sourceClass, String sourceMethod, String msg);
/**
* Trace a message, specifying source class and method, with an array of
* object arguments, if the logger is currently enabled for the given
* message level.
*
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used. The
* formatter uses java.text.MessageFormat style formatting to
* format parameters, so for example a format string "{0} {1}"
* would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
*/
void finest(String sourceClass, String sourceMethod, String msg, Object[] inserts);
void finest(String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex);
/**
* Log a message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param level
* One of the message level identifiers, e.g. SEVERE.
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message, may be null.
* @param thrown
* Throwable associated with log message.
*/
void log(int level, String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable thrown);
/**
* Log a trace message, specifying source class and method, with an array of
* object arguments and a throwable, if the logger is currently enabled for
* the given message level.
*
* @param level
* One of the message level identifiers, e.g. SEVERE.
* @param sourceClass
* Name of class that issued the logging request.
* @param sourceMethod
* Name of method that issued the logging request.
* @param msg
* The key in the message catalog for the message or the actual
* message itself. During formatting, if the logger has a mapping
* for the msg string, then the msg string is replaced by the
* value. Otherwise the original msg string is used. The
* formatter uses java.text.MessageFormat style formatting to
* format parameters, so for example a format string "{0} {1}"
* would format two inserts into the message.
* @param inserts
* Array of parameters to the message, may be null.
* @param ex
* Throwable associated with log message.
*/
void trace(int level, String sourceClass, String sourceMethod, String msg, Object[] inserts, Throwable ex);
/**
* Format a log message without causing it to be written to the log.
*
* @param msg
* The key in the message localization catalog for the message or
* the actual message itself. During formatting, if the logger
* has a mapping for the msg string, then the msg string is
* replaced by the localized value. Otherwise the original msg
* string is used. The formatter uses java.text.MessageFormat
* style formatting to format parameters, so for example a format
* string "{0} {1}" would format two inserts into the message.
* @param inserts
* Array of parameters to the message.
* @return The formatted message for the current locale.
*/
String formatMessage(String msg, Object[] inserts);
void dumpTrace();
}

View File

@@ -0,0 +1,155 @@
/*******************************************************************************
* Copyright (c) 2009, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0
* and the Eclipse Distribution License is available at
* https://www.eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Dave Locke - initial API and implementation and/or initial documentation
*/
package org.eclipse.paho.mqttv5.client.logging;
import java.lang.reflect.Method;
/**
* LoggerFactory will create a logger instance ready for use by the caller.
*
* The default is to create a logger that utilises the Java's built in
* logging facility java.util.logging (JSR47). It is possible to override
* this for systems where JSR47 is not available or an alternative logging
* facility is needed by using setLogger and passing the the class name of
* a logger that implements {@link Logger}
*/
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* A factory that returns a logger for use by the MQTT client.
*
* The default log and trace facility uses Java's build in log facility:-
* java.util.logging. For systems where this is not available or where
* an alternative logging framework is required the logging facility can be
* replaced using {@link org.eclipse.paho.mqttv5.client.logging.LoggerFactory#setLogger(String)}
* which takes an implementation of the {@link org.eclipse.paho.mqttv5.client.logging.Logger}
* interface.
*/
public class LoggerFactory {
/**
* Default message catalog.
*/
public final static String MQTT_CLIENT_MSG_CAT = "org.eclipse.paho.mqttv5.client.internal.nls.logcat";
private static final String CLASS_NAME = LoggerFactory.class.getName();
private static String overrideloggerClassName = null;
/**
* Default logger that uses java.util.logging.
*/
private static String jsr47LoggerClassName = JSR47Logger.class.getName();
/**
* Find or create a logger for a named package/class.
* If a logger has already been created with the given name
* it is returned. Otherwise a new logger is created. By default a logger
* that uses java.util.logging will be returned.
*
* @param messageCatalogName the resource bundle containing the logging messages.
* @param loggerID unique name to identify this logger.
* @return a suitable Logger.
*/
public static Logger getLogger(String messageCatalogName, String loggerID) {
String loggerClassName = overrideloggerClassName;
Logger logger = null;
if (loggerClassName == null) {
loggerClassName = jsr47LoggerClassName;
}
// logger = getJSR47Logger(ResourceBundle.getBundle(messageCatalogName), loggerID, null) ;
logger = getLogger(loggerClassName, ResourceBundle.getBundle(messageCatalogName), loggerID, null) ;
// }
if (null == logger) {
throw new MissingResourceException("Error locating the logging class", CLASS_NAME, loggerID);
}
return logger;
}
/**
* Return an instance of a logger
*
* @param the class name of the load to load
* @param messageCatalog the resource bundle containing messages
* @param loggerID an identifier for the logger
* @param resourceName a name or context to associate with this logger instance.
* @return a ready for use logger
*/
private static Logger getLogger(String loggerClassName, ResourceBundle messageCatalog, String loggerID, String resourceName) { //, FFDC ffdc) {
Logger logger = null;
Class logClass = null;
try {
logClass = Class.forName(loggerClassName);
} catch (NoClassDefFoundError ncdfe) {
return null;
} catch (ClassNotFoundException cnfe) {
return null;
}
if (null != logClass) {
// Now instantiate the log
try {
logger = (Logger)logClass.newInstance();
} catch (IllegalAccessException e) {
return null;
} catch (InstantiationException e) {
return null;
} catch (ExceptionInInitializerError e) {
return null;
} catch (SecurityException e) {
return null;
}
logger.initialise(messageCatalog, loggerID, resourceName);
}
return logger;
}
/**
* When run in JSR47, this allows access to the properties in the logging.properties
* file.
* If not run in JSR47, or the property isn't set, returns null.
* @param name the property to return
* @return the property value, or null if it isn't set or JSR47 isn't being used
*/
public static String getLoggingProperty(String name) {
String result = null;
try {
// Hide behind reflection as java.util.logging is guaranteed to be
// available.
Class logManagerClass = Class.forName("java.util.logging.LogManager");
Method m1 = logManagerClass.getMethod("getLogManager", new Class[]{});
Object logManagerInstance = m1.invoke(null, null);
Method m2 = logManagerClass.getMethod("getProperty", new Class[]{String.class});
result = (String)m2.invoke(logManagerInstance,new Object[]{name});
} catch(Exception e) {
// Any error, assume JSR47 isn't available and return null
result = null;
}
return result;
}
/**
* Set the class name of the logger that the LoggerFactory will load
* If not set getLogger will attempt to create a logger
* appropriate for the platform.
* @param loggerClassName - Logger implementation class name to use.
*/
public static void setLogger(String loggerClassName) {
LoggerFactory.overrideloggerClassName = loggerClassName;
}
}

View File

@@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0
* and the Eclipse Distribution License is available at
* https://www.eclipse.org/org/documents/edl-v10.php
*/
package org.eclipse.paho.mqttv5.client.logging;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
/**
* SimpleLogFormatter prints a single line
* log record in human readable form.
*/
public class SimpleLogFormatter extends Formatter {
private static final String LS = System.getProperty("line.separator");
/**
* Constructs a <code>SimpleFormatter</code> object.
*/
public SimpleLogFormatter() {
super();
}
/**
* Format the logrecord as a single line with well defined columns.
*/
public String format(LogRecord r) {
StringBuffer sb = new StringBuffer();
sb.append(r.getLevel().getName()).append("\t");
sb.append(MessageFormat.format("{0, date, yy-MM-dd} {0, time, kk:mm:ss.SSSS} ",
new Object[] { new Date(r.getMillis()) })+"\t");
String cnm = r.getSourceClassName();
String cn="";
if (cnm != null) {
int cnl = cnm.length();
if (cnl>20) {
cn = r.getSourceClassName().substring(cnl-19);
} else {
char[] sp = {' '};
StringBuffer sb1= new StringBuffer().append(cnm);
cn = sb1.append(sp,0, 1).toString();
}
}
sb.append(cn).append("\t").append(" ");
sb.append(left(r.getSourceMethodName(),23,' ')).append("\t");
sb.append(r.getThreadID()).append("\t");
sb.append(formatMessage(r)).append(LS);
if (null != r.getThrown()) {
sb.append("Throwable occurred: ");
Throwable t = r.getThrown();
PrintWriter pw = null;
try {
StringWriter sw = new StringWriter();
pw = new PrintWriter(sw);
t.printStackTrace(pw);
sb.append(sw.toString());
} finally {
if (pw != null) {
try {
pw.close();
} catch (Exception e) {
// ignore
}
}
}
}
return sb.toString();
}
/**
* Left justify a string.
*
* @param s the string to justify
* @param width the field width to justify within
* @param fillChar the character to fill with
*
* @return the justified string.
*/
public static String left(String s, int width, char fillChar) {
if (s.length() >= width) {
return s;
}
StringBuffer sb = new StringBuffer(width);
sb.append(s);
for (int i = width - s.length(); --i >= 0;) {
sb.append(fillChar);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,83 @@
# Properties file which configures the operation of the JDK logging facility.
#
# The configuration in this file is the suggesgted configuration
# for collecting trace for helping debug problems related to the
# Paho MQTT client. It configures trace to be continuosly collected
# in memory with minimal impact on performance.
#
# When the push trigger (by default a Severe level message) or a
# specific request is made to "push" the in memory trace then it
# is "pushed" to the configured target handler. By default
# this is the standard java.util.logging.FileHandler. The Paho Debug
# class can be used to push the memory trace to its target
#
# To enable trace either:
# - use this properties file as is and set the logging facility up
# to use it by configuring the util logging system property e.g.
#
# >java -Djava.util.logging.config.file=<location>\jsr47min.properties
#
# - This contents of this file can also be merged with another
# java.util.logging config file to ensure provide wider logging
# and trace including Paho trace
# Global logging properties.
# ------------------------------------------
# The set of handlers to be loaded upon startup.
# Comma-separated list of class names.
# - Root handlers are not enabled by default - just handlers on the Paho packages.
#handlers=java.util.logging.MemoryHandler,java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# Loggers and Handlers may override this level
#.level=INFO
# Loggers
# ------------------------------------------
# A memoryhandler is attached to the paho packages
# and the level specified to collected all trace related
# to paho packages. This will override any root/global
# level handlers if set.
org.eclipse.paho.mqttv5.client.handlers=java.util.logging.MemoryHandler
org.eclipse.paho.mqttv5.client.level=ALL
# It is possible to set more granular trace on a per class basis e.g.
#org.eclipse.paho.mqttv5.client.internal.ClientComms.level=ALL
# Handlers
# -----------------------------------------
# Note: the target handler that is associated with the MemoryHandler is not a root handler
# and hence not returned when getting the handlers from root. It appears accessing
# target handler programatically is not possible as target is a private variable in
# class MemoryHandler
java.util.logging.MemoryHandler.level=ALL
java.util.logging.MemoryHandler.size=10000
java.util.logging.MemoryHandler.push=ALL
java.util.logging.MemoryHandler.target=java.util.logging.FileHandler
#java.util.logging.MemoryHandler.target=java.util.logging.ConsoleHandler
# --- FileHandler ---
# Override of global logging level
java.util.logging.FileHandler.level=ALL
# Naming style for the output file:
# (The output file is placed in the directory
# defined by the "user.home" System property.)
# See java.util.logging for more options
java.util.logging.FileHandler.pattern=%h/ibm/paho/trace/paho%u.log
# Limiting size of output file in bytes:
java.util.logging.FileHandler.limit=200000
# Number of output files to cycle through, by appending an
# integer to the base file name:
java.util.logging.FileHandler.count=3
# Style of output (Simple or XML):
java.util.logging.FileHandler.formatter=org.eclipse.paho.mqttv5.client.logging.SimpleLogFormatter
# --- ConsoleHandler ---
# Override of global logging level
#java.util.logging.ConsoleHandler.level=INFO
#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
#java.util.logging.ConsoleHandler.formatter=org.eclipse.paho.mqttv5.client.logging.SimpleLogFormatter

View File

@@ -0,0 +1,5 @@
<body>
Provides helpers and utilities.
</body>