All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.Trace Maven / Gradle / Ivy

There is a newer version: 11.1
Show newest version
///////////////////////////////////////////////////////////////////////////////
//                                                                             
// JTOpen (IBM Toolbox for Java - OSS version)                                 
//                                                                             
// Filename: Trace.java
//                                                                             
// The source code contained herein is licensed under the IBM Public License   
// Version 1.0, which has been approved by the Open Source Initiative.         
// Copyright (C) 1997-2001 International Business Machines Corporation and     
// others. All rights reserved.                                                
//                                                                             
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;                                   // $D0A
import java.util.Hashtable;                                         // $W1A
import java.util.Vector;
import java.util.Enumeration;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.UnknownHostException;

/**
  Logs trace points and diagnostic messages.
  Each trace point and diagnostic message is logged by category.
  The valid categories are:
  
  • DATASTREAM
    This category is used by Toolbox classes to log data flow between the local host and the remote system. It is not intended for use by application classes.
  • DIAGNOSTIC
    This category is used to log object state information.
  • ERROR
    This category is used to log errors that cause an exception.
  • INFORMATION
    This category is used to track the flow of control through the code.
  • WARNING
    This category is used to log errors that are recoverable.
  • CONVERSION
    This category is used by Toolbox classes to log character set conversions between Unicode and native code pages. It is not intended for use by application classes.
  • PROXY
    This category is used by Toolbox classes to log data flow between the client and the proxy server. It is not intended for use by application classes.
  • PCML
    This category is used to determine how PCML interprets the data that is sent to and from the system.
  • JDBC
    This category is used to include JDBC data in the standard Toolbox trace.

The caller can enable or disable all tracing or specific trace categories. Enabling or disabling one category does not affect other categories. Once appropriate category traces are enabled, trace must be turned on to get trace data. For example,

      // By default, trace is disabled for all categories and
      // tracing is off.
      ..
      Trace.setTraceErrorOn(true);          // Enable error messages
      Trace.setTraceWarningOn(true);        // Enable warning messages

      Trace.setTraceOn(true);               // Turn trace on for all
                                            // Enabled categories

      ..
      Trace.setTraceOn(false);              // Turn trace off
      ..
      Trace.setTraceOn(true);               // Turn trace back on
      ..
      Trace.setTraceInformationOn(true);    // Enable informational messages.
                                            // Since trace is still on, no
                                            // other action is required to
                                            // get this data

      ..
      Trace.setTraceWarningOn(false);       // Disable warning messages.  Since
                                            // trace is still on, the other
                                            // categories will still be logged
  
The traces are logged to standard out by default. A file name can be provided to log to a file. File logging is only possible in an application as most browsers do not allow access to the local file system.

Trace data can also be specified by component. Trace data is always written to the default log but component tracing provides a way to write trace data to a separate log.

The following example logs data for Function123 into log file C:\Function123.log, and logs data for Function456 into log file C:\Function456.log. Data for these two components is also traced to the normal trace file (standard output in this case since that is the default for normal tracing). The result is three sets of data -- a file containing trace data for only Function123, a file containing trace data for only Function456, and standard output which records all trace data. In the example a Java String object is used to indicate the component, but any object can be used.

      // tracing is off by default
      ..
      String cmpF123 = "Function123";      // More efficient to create an object
      String cmpF456 = "Function456";      // than many String literals.

                                             // Specify where data should go
                                             // for the two components.
      Trace.setFileName(cmpF123, "C:\\Function123.log");
      Trace.setFileName(cmpF456, "C:\\Function456.log");

      Trace.setTraceInformationOn(true);     // Trace only the information category.
      Trace.setTraceOn(true);                // Turn tracing on.
      ..
      Trace.log(cmpF123, Trace.INFORMATION, "I am here");
      ..
      Trace.log(cmpF456, Trace.INFORMATION, "I am there");
      ..
      Trace.log(cmpF456, Trace.INFORMATION, "I am everywhere");
      ..
      Trace.setTraceOn(false);               // Turn tracing off.
  

Component tracing provides an easy way to write application specific trace data to a log or standard output. Any application and the Toolbox classes can use trace to log messages. With component tracing, application data can be easily separated from other data. For example,

      String myComponent = "com.myCompany";      // More efficient to create an object
                                                 // than many String literals.

      Trace.setFileName("C:\\bit.bucket");       // Send default trace data to
                                                 // a file.

      Trace.setTraceInformationOn(true);         // Enable information messages.
      Trace.setTraceOn(true);                    // Turn trace on.

      ...

                             // Since no file was specified, data for
                             // myComponent goes to standard output.
                             // Other information messages are sent to a file.
      Trace.log(myComponent, Trace.INFORMATION, "my trace data");

  

Two techniques can be used to log information:

      ..
      // Let the Trace method determine if logging should occur
      Trace.log(Trace.INFORMATION, "I got here...");
      ..
      // Pre-determine if we should log.  This may be more efficient
      // if a lot of processing in needed to generate the trace data.
      if (Trace.isTraceOn() && Trace.isTraceInformationOn())
      {
            Trace.log(Trace.INFORMATION, "I got here...");
      }
  

It is suggested that programs provide some mechanism to enable tracing at run-time, so that the modification and recompilation of code is not necessary. Two possibilities for that mechanism are a command line argument (for applications) or a menu option (for applications and applets).

In addition, tracing can be set using the "com.ibm.as400.access.Trace.category" and "com.ibm.as400.access.Trace.file" system properties.

Note: This class can exploit a standard Java Logger if one is defined in the JVM (per JSR 47, package java.util.logging, added in J2SE 1.4). See {@link #LOGGER_NAME LOGGER_NAME}. **/ public class Trace implements Runnable { private static final String CLASSNAME = "com.ibm.as400.access.Trace"; private static final int DEFAULT_MONITOR_PORT = 55555; static boolean traceOn_; //@P0C static boolean traceInfo_; static boolean traceWarning_; static boolean traceError_; static boolean traceDiagnostic_; static boolean traceDatastream_; static boolean traceConversion_; static boolean traceProxy_; // @D0A static boolean traceThread_; // @D3A static boolean traceJDBC_; // @D5A static boolean tracePCML_; static boolean showChars_ = false; private static int mostRecentTracingChange_; // either 0 (no action), TURNED_TRACE_OFF, or TURNED_TRACE_ON private static final int TURNED_TRACE_ON = 1; private static final int TURNED_TRACE_OFF = 2; private static boolean aTraceCategoryHasBeenActivated_ = false; // goes to 'true' when any setTraceXxx() method has been called with argument 'true' private static String fileName_ = null; private static PrintWriter destination_ = new PrintWriter(System.out, true); // never null private static boolean userSpecifiedDestination_ = false; // true if setFileName() or setPrintWriter() was called with a non-null argument private static Hashtable printWriterHash_ = new Hashtable(); // @W1A private static Hashtable fileNameHash_ = new Hashtable(); // @W1A private static SimpleDateFormat timeStampFormatter_ = new SimpleDateFormat( "EEE MMM d HH:mm:ss:SSS z yyyy" ); /** 'Data stream' trace category. This category is used by Toolbox classes to log data flow between the local host and the remote system. It is not intended for use by application classes. **/ public static final int DATASTREAM = 0; //private static final int FIRST_ONE = 0; // @W1A /** 'Diagnostic message' trace category. This category is used to log object state information. **/ public static final int DIAGNOSTIC = 1; /** 'Error message' trace category. This category is used to log errors that cause an exception. **/ public static final int ERROR = 2; /** 'Information message' trace category. This category is used to track the flow of control through the code. **/ public static final int INFORMATION = 3; /** 'Warning message' trace category. This category is used to log errors that are recoverable. **/ public static final int WARNING = 4; /** 'Character set conversion' trace category. This category is used by Toolbox classes to log conversions between Unicode and native code pages. It is not intended for use by application classes. **/ public static final int CONVERSION = 5; /** 'Proxy' trace category. This category is used by Toolbox classes to log data flow between the client and the proxy server. It is not intended for use by application classes. **/ public static final int PROXY = 6; // @D0A /** 'PCML' trace category. This category is used to determine how PCML interprets the data that is sent to and from the system. **/ public static final int PCML = 7; // @D8A /** 'JDBC' trace category. This category is used by the Toolbox JDBC driver to determine whether or not JDBC data should be included in the standard Toolbox trace. This setting is independent of what is set using the {@link java.sql.DriverManager DriverManager} class. **/ public static final int JDBC = 8; // This is used so we don't have to change our bounds checking every time we add a new trace category. //private static final int LAST_ONE = 9; // @D3A @D8C // The following are trace categories which cannot be log()-ed to directly. /* Thread trace category. This category is used to enable or disable tracing of thread information. This is useful when debugging multi-threaded applications. Trace information cannot be directly logged to this category. */ // @E1D private static final int THREAD = 99; // @D3A /* All trace category. This category is used to enable or disable tracing for all of the other categories at once. Trace information cannot be directly logged to this category. */ // @E1D private static final int ALL = 100; //@D2A /** Name of the instance of java.util.logging.Logger that the Toolbox uses. If no Logger by this name exists in the JVM, then traditional Toolbox tracing is done. To activate a Toolbox logger, the application can simply call Logger.getLogger(Trace.LOGGER_NAME).
Note: This constant resolves to the value com.ibm.as400.access. **/ public static final String LOGGER_NAME = "com.ibm.as400.access"; // Design note: We needed to segregate the Logger logic into a separate class. The Java logging package doesn't exist prior to JDK 1.4, so if we're executing in an older JVM, we get SecurityException's if the JVM sees _any_ runtime reference to a java.util.logging class. private static ToolboxLogger logger_ = null; private static boolean firstCallToFindLogger_ = true; private static boolean JDK14_OR_HIGHER; private static PrintWriter globalPw = null; // @D0A static { try { Class.forName("java.util.logging.LogManager"); // Class added in JDK 1.4. JDK14_OR_HIGHER = true; // If we got this far, we're on JDK 1.4 or higher. } catch (Throwable e) { // We're not on JDK 1.4 or higher, JDK14_OR_HIGHER = false; // so don't even try to get the Toolbox Logger. } loadTraceProperties (); } // This is only here to prevent anyone from instantiating a Trace object. private Trace() { } /** Returns the trace file name. @return The file name if logging to file. If logging to System.out, null is returned. **/ public static String getFileName() { return fileName_; } /** Returns the trace file name for the specified component. Null is returned if no file name has been set for the component. * @param component @return The file name for the specified component. Null is returned if no file name has been set for the component. **/ public static String getFileName(Object component) { if (component == null) throw new NullPointerException("component"); return(String) fileNameHash_.get(component); } /** Returns the PrintWriter object. @return The PrintWriter object for the trace data output. **/ public static PrintWriter getPrintWriter() { return destination_; } /** Returns the print writer object for the specified component. Null is returned if no writer or file name has been set. If a file name for a component is set, that component automatically gets a print writer. * @param component @return The print writer object for the specified component. If no writer or file name has been set, null is returned. **/ public static PrintWriter getPrintWriter(Object component) { if (component == null) throw new NullPointerException("component"); return(PrintWriter) printWriterHash_.get(component); } //@D2A /** Indicates if all of the tracing categories are enabled. @return true if all categories are traced; false otherwise. **/ public static final boolean isTraceAllOn() { return traceConversion_ && traceDatastream_ && traceDiagnostic_ && traceError_ && traceInfo_ && traceProxy_ && traceWarning_ && traceThread_ && traceJDBC_ && tracePCML_; //@D3C @D5C } /** Indicates if character set conversion tracing is enabled. @return true if conversions are traced; false otherwise. **/ public static final boolean isTraceConversionOn() { return traceConversion_; } /** Indicates if data stream tracing is enabled. @return true if data streams are traced; false otherwise. **/ public static final boolean isTraceDatastreamOn() { return traceDatastream_; } /** Indicates if diagnostic tracing is enabled. @return true if diagnostic messages are traced; false otherwise. **/ public static final boolean isTraceDiagnosticOn() { return traceDiagnostic_; } /** Indicates if error tracing is enabled. @return true if error messages are traced; false otherwise. **/ public static final boolean isTraceErrorOn() { return traceError_; } /** Indicates if information tracing is enabled. @return true if information messages are traced; false otherwise. **/ public static final boolean isTraceInformationOn() { return traceInfo_; } /** * Indicates if JDBC tracing is enabled. * @return true if JDBC messages are traced; false otherwise. **/ public static final boolean isTraceJDBCOn() // @D5A { return traceJDBC_; } /** Indicates if overall tracing is enabled. If this is false, no tracing occurs. @return true if tracing is enabled; false otherwise. **/ public static final boolean isTraceOn() { return traceOn_; } /** Indicates if tracing is enabled for the specified category. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @return true if tracing for the category is enabled; false otherwise. **/ public static final boolean isTraceOn(int category) { switch (category) { case DATASTREAM: return traceDatastream_; case DIAGNOSTIC: return traceDiagnostic_; case ERROR: return traceError_; case INFORMATION: return traceInfo_; case WARNING: return traceWarning_; case CONVERSION: return traceConversion_; case PROXY: return traceProxy_; case PCML: return tracePCML_; case JDBC: return traceJDBC_; default: return false; } } /** * Indicates if PCML tracing is enabled. * @return true if PCML messages are traced; false otherwise. **/ public static final boolean isTracePCMLOn() // @D5A { return tracePCML_; } // @D0A /** Indicates if proxy tracing is enabled. @return true if proxy tracing is enabled; false otherwise. **/ public static final boolean isTraceProxyOn() { return traceProxy_; } // @D3A /** Indicates if thread tracing is enabled. @return true if thread tracing is enabled; false otherwise. **/ public static final boolean isTraceThreadOn() { return traceThread_; } /** Indicates if warning tracing is enabled. @return true if warning messages are traced; false otherwise. **/ public static final boolean isTraceWarningOn() { return traceWarning_; } // Note: If the properties file specifies the "com.ibm.as400.access.Trace.file" property, then we will disregard any existing Toolbox Logger. // @D0A static void loadTraceProperties () { // Load and apply the trace categories system property. // Warn if they specified "categories" (rather than "category") for the property name. String categories0 = SystemProperties.getProperty(SystemProperties.TRACE_CATEGORIES); if (categories0 != null) { setTraceCategories(categories0); if (Trace.traceOn_) Trace.log(Trace.WARNING, "Incorrect tracing property name specified: " + SystemProperties.TRACE_CATEGORIES); } String categories = SystemProperties.getProperty(SystemProperties.TRACE_CATEGORY); if (categories0 == null || categories != null) setTraceCategories(categories); // // Determine if characters should be shown in trace // String showCharsString = SystemProperties.getProperty(SystemProperties.TRACE_SHOW_CHARS); if (showCharsString !=null && showCharsString.equalsIgnoreCase("true")) { showChars_ = true; } // Load and apply the trace file system property. String file = SystemProperties.getProperty (SystemProperties.TRACE_FILE); if (file != null) { try { setFileName (file); synchronized (destination_) { destination_.println("Toolbox for Java - JDBC " + AS400JDBCDriver.JDBC_MAJOR_VERSION_ + "." + AS400JDBCDriver.JDBC_MINOR_VERSION_ + " " + Copyright.version); destination_.println(getJvmInfo()); /* @B1A */ destination_.println(); logLoadPath(CLASSNAME, activeTraceCategory()); } } catch (IOException e) { if (isTraceOn ()) { String msg = "Trace file not valid: " + file; System.err.println(msg); e.printStackTrace(System.err); Trace.log(Trace.WARNING, msg, e); } } } // Load and apply the trace enabled system property. String enabled = SystemProperties.getProperty (SystemProperties.TRACE_ENABLED); if (enabled != null) { boolean value = Boolean.valueOf(enabled).booleanValue(); traceOn_ = value; } startTraceMonitorIfNeeded(); logLoadPath(CLASSNAME); } /** Logs the path where the ClassLoader found the specified class. Each specific class is logged no more than once. @param className The package-qualified class name. **/ static final void logLoadPath(String className) { logLoadPath(className, -1); } static final void logLoadPath(String className, int category) { if (((category > -1)|| traceDiagnostic_) && className != null) { String loadPath = null; try { ClassLoader loader = Class.forName(className).getClassLoader(); if (loader != null) { String resourceName = className.replace('.', '/') + ".class"; java.net.URL resourceUrl = loader.getResource(resourceName); if (resourceUrl != null) { loadPath = resourceUrl.getPath(); // Note: The following logic strips the entry name from the end of the path. // int delimiterPos = loadPath.lastIndexOf('!'); // if (delimiterPos != -1) loadPath = loadPath.substring(0, delimiterPos); } } } catch (Throwable t) { String message = "Unable to determine load path for class " + className; logData(null, ERROR, message, t); } String message = "Class " + className + " was loaded from " + loadPath; if (category > -1) { logData(null, category, message, null); } else { logData(null, DIAGNOSTIC, message, null); } } } // Log time stamp information in the trace. private static void logTimeStamp(Object component, PrintWriter pw) //@W1C { if (component != null) //@W1A if (component.toString() != null) //@W1A pw.print("[" + component.toString() + "] "); //@W1A if (traceThread_) //@D3A @W1C { //@D3A @W1C pw.print(Thread.currentThread().toString()); //@D3A @W1C pw.print(" "); //@D3A @W1C } //@D3A @W1C synchronized (timeStampFormatter_) // date formats are not synchronized { pw.print(timeStampFormatter_.format(new Date())); // @W1C } pw.print(" "); // @W1C } // Log time stamp information in the trace. private static void logTimeStamp(Object component, StringBuffer buf) { if (component != null) if (component.toString() != null) buf.append("[" + component.toString() + "] "); if (traceThread_) { buf.append(Thread.currentThread().toString()); buf.append(" "); } synchronized (timeStampFormatter_) // date formats are not synchronized { buf.append(timeStampFormatter_.format(new Date())); } buf.append(" "); } private static void logSource(Object source, StringBuffer buffer) { //@L8 if(source==null) return; buffer.append('['); String simpleName =source.getClass().getName(); int dotIndex = simpleName.lastIndexOf('.'); if (dotIndex > 0) { simpleName = simpleName.substring(dotIndex+1); } buffer.append(simpleName); buffer.append('@'); buffer.append(source.hashCode()); buffer.append("] "); } private static void logSource(Object source, PrintWriter writer) { //@L8 if(source==null) return; writer.print('['); String simpleName =source.getClass().getName(); int dotIndex = simpleName.lastIndexOf('.'); if (dotIndex > 0) { simpleName = simpleName.substring(dotIndex+1); } writer.print(simpleName); writer.print('@'); writer.print(source.hashCode()); writer.print("] "); } // This is the routine that actually writes to the log. private static final void logData(Object component, int category, String message, Throwable e) { logData(component, category, null, message, e); } private static final void logData(Object component, int category, Object source, //@L8 String message, Throwable e) { // See if tracing is activated for the specified category. if ((traceOn_ && traceCategory(category)) || (findLogger() && logger_.isLoggable(category))) { if (message == null) message = "(null)"; // Two different cases: Either traditional Toolbox trace, or Java Logging. if (logger_ == null || userSpecifiedDestination_) // traditional trace { // First, write to the default log synchronized(destination_) { // If component tracing is being used, log the component name to // the default log as well as the specific component log. if (component != null && getFileName(component) != null) //$W2A { //$W2A logTimeStamp(component, destination_); //$W2A logSource(source, destination_); //@L8 destination_.println(message); //$W2A } //$W2A else //$W2A { //$W2A // Only trace to the default log if we are not doing component // tracing. This will avoid duplicate messages in the default // log. if (component == null) //$W2A { //$W2A logTimeStamp(null, destination_); //$W2A logSource(source, destination_); //@L8 destination_.println(message); //$W2A } //$W2A } //$W2A if (e != null) e.printStackTrace(destination_); else if (category == ERROR) new Throwable().printStackTrace(destination_); } if (component != null) { PrintWriter pw = (PrintWriter) printWriterHash_.get(component); if (pw == null) { if (globalPw == null) { globalPw = new PrintWriter(System.out, true); } pw = globalPw; printWriterHash_.put(component, pw); } synchronized(pw) { logTimeStamp(component, pw); logSource(source, pw); //@L8 pw.println(message); if (e != null) e.printStackTrace(pw); else if (category == ERROR) new Throwable().printStackTrace(pw); } } } // traditional Toolbox tracing else // We are logging to a Java Logger. { // Log to the Logger instead of to destination_. // Don't bother splitting up into separate component-specific trace files. StringBuffer buf = new StringBuffer(); logTimeStamp(component, buf); logSource(source, buf); //@L8 buf.append(message); if (e != null) { logger_.log(category, buf.toString(), e); } else if (category == ERROR) { logger_.log(category, buf.toString(), new Throwable()); } else { logger_.log(category, buf.toString()); } } // using a Java Logger } else {} // tracing is not activated for the specified category, so do nothing } /** Logs a message in the specified category. If the category is disabled, nothing is logged. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. **/ public static final void log(int category, String message) { logData(null, category, null, message, null); } /** * Logs a message in the specified category. If the category is disabled * nothing is logged. * @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. * @param message The message to log. * @param source Object that is posting this message. **/ public static final void log(int category, Object source, String message) { //@L8 logData(null, category, source, message, null); } /** Logs a message for the specified component for the specified category. If the category is disabled, nothing is logged. If no print writer or file name has been set for the component, nothing is logged. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. **/ public static final void log(Object component, int category, String message) { logData(component, category, null, message, null); //@L8 } /** Logs a message for the specified component for the specified category. If the category is disabled, nothing is logged. If no print writer or file name has been set for the component, nothing is logged. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param source The object posting this message. **/ public static final void log(Object component, int category, Object source, String message) { //@L8 logData(component, category, source, message, null); } /** * Logs a message in the specified category. If the category is disabled, nothing is logged. * @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. * @param message The message to log. * @param e The Throwable object that contains the stack trace to log. **/ public static final void log(int category, String message, Throwable e) { logData(null, category, null, message, e); //@L8 } /** * Logs a message in the specified category. If the category is disabled, nothing is logged. * @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. * @param message The message to log. * @param e The Throwable object that contains the stack trace to log. * @param source The object posting this message. **/ public static final void log(int category, Object source, String message, Throwable e) { //@L8 logData(null, category, source, message, e ); } /** Logs a message in the specified category for the specified component. If the category is disabled, nothing is logged. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param e The Throwable object that contains the stack trace to log. **/ public static final void log(Object component, int category, String message, Throwable e) { logData(component, category, null, message, e); //@L8 } /** Logs a message in the specified category. If the category is disabled, nothing is logged. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param e The Throwable object that contains the stack trace to log. **/ public static final void log(int category, Throwable e) { if (e.getLocalizedMessage() == null) //$B2A log(category, "Exception does not contain a message.", e); //$B2A else //$B2A log(category, e.getLocalizedMessage (), e); //$B2C } /** Logs a message in the specified category for the specified component. If the category is disabled, nothing is logged. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param e The Throwable object that contains the stack trace to log. **/ public static final void log(Object component, int category, Throwable e) { if (e.getLocalizedMessage() == null) //$B2A log(component, category, "Exception does not contain a message.", e); //$B2A else //$B2A log(component, category, e.getLocalizedMessage (), e); //$B2C } /** Logs a message and an integer value in the specified category. If the category is disabled, nothing is logged. The integer value is appended to the end of the message, preceded by two blanks. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The integer value to log. **/ public static final void log(int category, String message, int value) { if (message == null) message = "(null)"; log(category, message + " " + value); } /** Logs a message and an integer value in the specified category. If the category is disabled, nothing is logged. The integer value is appended to the end of the message, preceded by two blanks. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The integer value to log. @param source The object posting this message. **/ public static final void log(int category, Object source, String message, int value) { //@L8 if (message == null) message = "(null)"; log(category, source, message + " " + value); } /** Logs a message and a String value in the specified category. If the category is disabled, nothing is logged. The String value is appended to the end of the message, preceded by two blanks. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The String value to log. **/ public static final void log(int category, String message, String value) { if (message == null) message = "(null)"; log(category, message + " " + (value == null ? "(null)" : value)); } /** Logs a message and an integer value in the specified category for the specified component. If the category is disabled, nothing is logged. The integer value is appended to the end of the message, preceded by two blanks. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The integer value to log. **/ public static final void log(Object component, int category, String message, int value) { if (message == null) message = "(null)"; log(component, category, message + " " + value); } /** Logs a SSL message based on the SSLException integer values to the specified category. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param sslCategory The SSLException category. @param sslError The SSLException error. @param sslInt1 The SSLException Int1. **/ static final void logSSL(int category, int sslCategory, int sslError, int sslInt1) //$B1A { log(Trace.ERROR, "An SSLException occurred, turn on DIAGNOSITC tracing to see the details."); log(category, "SSL Category: " + sslCategory); log(category, "SSL Error: " + sslError); log(category, "SSL Int1: " + sslInt1); } /** Logs a message and a boolean value in the specified category. If the category is disabled, nothing is logged. The boolean value is appended to the end of the message, preceded by two blanks. true is logged for true, and false is logged for false. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The boolean data to log. **/ public static final void log(int category, String message, boolean value) { if (message == null) message = "(null)"; log(category, message + " " + value); } /** Logs a message and a boolean value in the specified category. If the category is disabled, nothing is logged. The boolean value is appended to the end of the message, preceded by two blanks. true is logged for true, and false is logged for false. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The boolean data to log. @param source The object posting this message. **/ public static final void log(int category, Object source, String message, boolean value) { if (message == null) message = "(null)"; log(category, source, message + " " + value); } /** Logs a message and a boolean value in the specified category for the specified component. If the category is disabled, nothing is logged. The boolean value is appended to the end of the message, preceded by two blanks. true is logged for true, and false is logged for false. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param value The boolean data to log. **/ public static final void log(Object component, int category, String message, boolean value) { if (message == null) message = "(null)"; log(component, category, message + " " + value); } /** Logs a message and byte data in the specified category. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param data The bytes to log. **/ public static final void log(int category, String message, byte[] data) { if (data == null) { if (message == null) message = "(null)"; log(category, message + " " + "(null)"); } else { log(category, message, data, 0, data.length); } } /** Logs a message and byte data in the specified category. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. * @param source @param message The message to log. @param data The bytes to log. **/ public static final void log(int category, Object source, String message, byte[] data) { //@L8 if (data == null) { if (message == null) message = "(null)"; log(category, source, message + " " + "(null)"); } else { log(category, source, message, data, 0, data.length); } } /** Logs a message and byte data in the specified category for the specified component. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param data The bytes to log. **/ public static final void log(Object component, int category, String message, byte[] data) { if (data == null) { if (message == null) message = "(null)"; log(component, category, message + " " + "(null)"); } else { log(component, category, message, data, 0, data.length); } } /** Logs a message and byte data in the specified category. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param data The bytes to log. @param offset The start offset in the data. @param length The number of bytes of data to log. **/ public static final void log(int category, String message, byte[] data, int offset, int length) { if ((traceOn_ && traceCategory(category)) || (findLogger() && logger_.isLoggable(category))) { if (logger_ == null || userSpecifiedDestination_) // traditional trace { // log to destination_ synchronized(destination_) { logTimeStamp(null, destination_); if (message != null) destination_.println(message); printByteArray(destination_, data, offset, length); if (category == ERROR) { new Throwable().printStackTrace(destination_); } } } else // log to logger_ { StringBuffer buf = new StringBuffer(); logTimeStamp(null, buf); printByteArray(buf, data, offset, length); if (category == ERROR) { logger_.log(category, buf.toString(), new Throwable()); } else { logger_.log(category, buf.toString()); } } } } /** Logs a message and byte data in the specified category. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param data The bytes to log. @param offset The start offset in the data. @param length The number of bytes of data to log. **/ private static final void log(int category, Object source, String message, byte[] data, int offset, int length) { //@L8 if ((traceOn_ && traceCategory(category)) || (findLogger() && logger_.isLoggable(category))) { if (logger_ == null || userSpecifiedDestination_) // traditional trace { // log to destination_ synchronized(destination_) { logTimeStamp(null, destination_); logSource(source, destination_); if (message != null) destination_.println(message); printByteArray(destination_, data, offset, length); if (category == ERROR) { new Throwable().printStackTrace(destination_); } } } else // log to logger_ { StringBuffer buf = new StringBuffer(); logTimeStamp(null, buf); logSource(source, buf); printByteArray(buf, data, offset, length); if (category == ERROR) { logger_.log(category, buf.toString(), new Throwable()); } else { logger_.log(category, buf.toString()); } } } } /** Logs a message and byte data in the specified category for the specified component. If the category is disabled, nothing is logged. The byte data is appended to the end of the message, sixteen bytes per line. @param component The component to trace. @param category The message category [DATASTREAM, DIAGNOSTIC, ERROR, INFORMATION, WARNING, CONVERSION, PROXY, JDBC]. @param message The message to log. @param data The bytes to log. @param offset The start offset in the data. @param length The number of bytes of data to log. **/ public static final void log(Object component, int category, String message, byte[] data, int offset, int length) { if (message == null) message = "(null)"; if (component == null) { throw new NullPointerException("component"); } if ((traceOn_ && traceCategory(category)) || (findLogger() && logger_.isLoggable(category))) { if (logger_ == null || userSpecifiedDestination_) // traditional trace { // log to component-specific trace file PrintWriter pw = (PrintWriter) printWriterHash_.get(component); if (pw == null) { if (globalPw == null) { globalPw = new PrintWriter(System.out, true); } pw = globalPw; printWriterHash_.put(component, pw); } synchronized(pw) { logTimeStamp(component, pw); pw.println(message); printByteArray(pw, data, offset, length); if (category == ERROR) { new Throwable().printStackTrace(pw); } } } log(category, message, data, offset, length); } } // Logs data from a byte array starting at offset for the length specified. // Output sixteen bytes per line, two hexadecimal digits per byte, one // space between bytes. static void printByteArray(PrintWriter pw, byte[] data, int offset, int length) { StringBuffer ebcdicInfo = null; StringBuffer asciiInfo = null; if (showChars_) { ebcdicInfo = new StringBuffer(); asciiInfo = new StringBuffer(); } if (data == null) { pw.println("(null)"); return; } for (int i = 0; i < length; i++, offset++) { pw.print(toHexString(data[offset])); pw.print(" "); if (ebcdicInfo != null && asciiInfo !=null ) { ebcdicInfo.append(toEbcdicString(data[offset])); asciiInfo.append(toAsciiString(data[offset])); } if ((i & 0x0F ) == 0x0F) { if (ebcdicInfo != null && asciiInfo !=null) { pw.print(" | "); pw.print(ebcdicInfo.toString()); pw.print(" | "); pw.print(asciiInfo.toString()); pw.print(" |"); ebcdicInfo.setLength(0); asciiInfo.setLength(0); } pw.println(); // start a new line } } if (((length - 1) & 0x0F) != 0x0F) { if (ebcdicInfo != null && asciiInfo !=null) { int extraPad = length % 16; for (int i = extraPad; i < 16; i++) { pw.print(" "); } pw.print(" | "); pw.print(ebcdicInfo.toString()); for (int i = extraPad; i < 16; i++) { pw.print(" "); } pw.print(" | "); pw.print(asciiInfo.toString()); for (int i = extraPad; i < 16; i++) { pw.print(" "); } pw.print(" |"); ebcdicInfo.setLength(0); asciiInfo.setLength(0); } // Finish the line of data. pw.println(); } } // Logs data from a byte array. // Output sixteen bytes per line, two hexadecimal digits per byte, one // space between bytes. static void printByteArray(StringBuffer buf, byte[] data) { printByteArray(buf, data, 0, data.length); } // Logs data from a byte array starting at offset for the length specified. // Output sixteen bytes per line, two hexadecimal digits per byte, one // space between bytes. static void printByteArray(StringBuffer buf, byte[] data, int offset, int length) { if (data == null) { buf.append("(null)\n"); return; } for (int i = 0; i < length; i++, offset++) { buf.append(toHexString(data[offset])); buf.append(" "); if ((i & 0x0F ) == 0x0F) { buf.append("\n"); // start a new line } } if (((length - 1) & 0x0F) != 0x0F) { // Finish the line of data. buf.append("\n"); } } // Hexadecimal string representations of all possible values for a single byte. private static final String[] HEX_BYTE_ARRAY = new String[] { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" }; /** Returns a string representation of the byte argument, as 2 hexadecimal digits. @param b A byte to be converted to a string. @return The 2-digit hexadecimal string representation of the byte argument. **/ public static final String toHexString(byte b) { return HEX_BYTE_ARRAY[0x00FF & b]; } // Hexadecimal string representations of all possible values for a single byte. private static final String[] ASCII_BYTE_ARRAY = new String[] { /*00*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*10*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*20*/ " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", /*30*/ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", /*40*/ "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", /*50*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", /*60*/ "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", /*70*/ "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", ".", /*80*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*90*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*a0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*b0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*c0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*d0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*e0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*f0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." }; /** Returns a string representation of the byte argument, as 1 ascii digits. @param b A byte to be converted to a string. @return The 1-digit ascii string representation of the byte argument. **/ public static final String toAsciiString(byte b) { return ASCII_BYTE_ARRAY[0x00FF & b]; } // Hexadecimal string representations of all possible values for a single byte. private static final String[] EBCDIC_BYTE_ARRAY = new String[] { /*00*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*10*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*20*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*30*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*40*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "[", ".", "<", "(", "+", "!", /*50*/ "&", ".", ".", ".", ".", ".", ".", ".", ".", ".", "]", "$", "*", ")", ";", "^", /*60*/ "-", "/", ".", ".", ".", ".", ".", ".", ".", ".", "|", ",", "%", "_", ">", "?", /*70*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", "`", ":", "#", "@", "'", "=", "\"", /*80*/ ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", ".", ".", ".", ".", ".", ".", /*90*/ ".", "j", "k", "l", "m", "n", "o", "p", "q", "r", ".", ".", ".", ".", ".", ".", /*a0*/ ".", ".", "s", "t", "u", "v", "w", "x", "y", "z", ".", ".", ".", ".", ".", ".", /*b0*/ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", /*c0*/ "{", "A", "B", "C", "D", "E", "F", "G", "H", "I", ".", ".", ".", ".", ".", ".", /*d0*/ "}", "J", "K", "L", "M", "N", "O", "P", "Q", "R", ".", ".", ".", ".", ".", ".", /*e0*/ "\\", ".", "S", "T", "U", "V", "W", "X", "Y", "Z", ".", ".", ".", ".", ".", ".", /*f0*/ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ".", ".", ".", ".", "." }; /** Returns a string representation of the byte argument, as 1 ebcdic digits. @param b A byte to be converted to a string. @return The 1-digit ebcdic string representation of the byte argument. **/ public static final String toEbcdicString(byte b) { return EBCDIC_BYTE_ARRAY[0x00FF & b]; } /** Returns a string representation of the byte-array argument, as a sequence of hexadecimal digits. @param bytes A byte array to be converted to a string. @return The hexadecimal string representation of the byte array argument. **/ public static final String toHexString(byte[] bytes) { if (bytes == null) throw new NullPointerException("bytes"); StringBuffer buf = new StringBuffer(); for (int i=0; iNote: "thread" is not a separate trace category. That is, simply calling setTraceThreadOn(true) by itself will not cause any trace messages to be generated. Rather, it will cause additional thread-related information to be included in trace messages generated for other trace categories, such as "diagnostic" and "information". @param traceThread If true, thread tracing is on; otherwise, thread tracing is off. @see Trace#setTraceOn **/ public static void setTraceThreadOn(boolean traceThread) { if (traceThread_ != traceThread) { traceThread_ = traceThread; if (traceThread) aTraceCategoryHasBeenActivated_ = true; if (findLogger()) logger_.setLevel(); } } /** Sets warning tracing on or off. The actual tracing does not happen unless tracing is enabled. @param traceWarning If true, warning tracing is enabled; otherwise, warning tracing is disabled. @see Trace#setTraceOn **/ public static void setTraceWarningOn(boolean traceWarning) { if (traceWarning_ != traceWarning) { traceWarning_ = traceWarning; if (traceWarning) aTraceCategoryHasBeenActivated_ = true; if (findLogger()) logger_.setLevel(); } } // Indicates if this category is being traced or not. private static boolean traceCategory(int category) // @D5C { boolean trace = false; switch (category) { case INFORMATION: trace = traceInfo_; break; case WARNING: trace = traceWarning_; break; case ERROR: trace = traceError_; break; case DIAGNOSTIC: trace = traceDiagnostic_; break; case DATASTREAM: trace = traceDatastream_; break; case CONVERSION: trace = traceConversion_; break; case PROXY: trace = traceProxy_; break; case PCML: // @D8A trace = tracePCML_; // @D8A break; // @D8A case JDBC: trace = traceJDBC_; break; default: throw new ExtendedIllegalArgumentException("category (" + Integer.toString(category) + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); } return trace; } /** * Determines if the user has requested the trace monitor be started. If so, starts the * monitor thread. */ private static void startTraceMonitorIfNeeded() { String shouldMonitor = SystemProperties.getProperty(SystemProperties.TRACE_MONITOR); if (shouldMonitor==null) return; //Not set, return if (Boolean.valueOf(shouldMonitor).equals(Boolean.TRUE)) { try { Thread monitor = new Thread(new Trace(), "Toolbox Trace Monitor"); monitor.setDaemon(true); //So this thread ends with the JVM monitor.start(); } catch (Exception e) { System.err.println("Failed to start trace monitor: " + e.getMessage()); e.printStackTrace(System.err); } } } /** * Handle the commands submitted to the monitor thread. * @param commands */ private static String handleTraceStatusChange(String command) { int index = command.indexOf('='); if (index<0) { String msg = "Invalid trace command: " + command; System.err.println(msg); logData(null, ERROR, msg, null); return msg; } String property = command.substring(0,index); String value = command.substring(index+1); if (value.length()==0) value = null; //com.ibm.as400.access.Trace.category= if (property.equals(SystemProperties.TRACE_CATEGORY)) { setTraceCategories(value); } else if (property.equals(SystemProperties.TRACE_FILE)) { if (value==null || !value.equals(fileName_)) { try { setFileName(value); } catch (IOException e) { String msg = "Failed to set file name to "+value+": " + e.getMessage(); System.err.println(msg); e.printStackTrace(System.err); return msg; } } } else return ("Unrecognized command: " + command); return "Command processed: " + command; } /** * Listens for trace status changes. */ public void run() { int port; try { String portNum = SystemProperties.getProperty(SystemProperties.TRACE_MONITOR_PORT); if (portNum!=null) port = Integer.parseInt(portNum); else port = DEFAULT_MONITOR_PORT; } catch (Exception e) { System.err.println("Failed to get TRACE_MONITOR_PORT property: " + e.getMessage()); e.printStackTrace(System.err); return; } try { ServerSocket monitorSocket_ = new ServerSocket(port, 1); //Only 1 connection at a time while (true) { Socket currentSocket = monitorSocket_.accept(); //Wait for connect requests. BufferedReader in = new BufferedReader(new InputStreamReader(currentSocket.getInputStream())); PrintWriter out = new PrintWriter(currentSocket.getOutputStream(), true); String command = in.readLine(); if (command != null) { String result = handleTraceStatusChange(command); out.println(result); } currentSocket.close(); } } catch (Exception e) { System.err.println("Exception in trace monitor daemon: " + e.getMessage()); e.printStackTrace(System.err); } } /** * Update trace parameters. * @param args */ public static void main(String[] args) { if (args.length<3) printUsage(); else { int port = 0; try { port = Integer.parseInt(args[1]); // assume the 2nd arg is portNum } catch (Exception e) { System.err.println("Invalid port specified (" + args[1] + ")"); e.printStackTrace(System.err); return; } try { for (int i=2; i





© 2015 - 2024 Weber Informatics LLC | Privacy Policy