TraceHelper.java
/*
** Module : TraceHelper.java
** Abstract : helper methods to trace method invocations
**
** Copyright (c) 2006-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
** 001 GES 20060723 @28170 Provides helper methods to trace method
** invocations.
** 002 GES 20090422 @41916 Converted to standard string formatting.
** 003 GES 20090424 @41974 Import change.
** 004 ECF 20150715 Replace StringBuffer with StringBuilder.
** 005 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
import java.util.logging.*;
import com.goldencode.p2j.util.logging.*;
import com.goldencode.util.*;
/**
* Helper methods to trace method invocations.
*/
public class TraceHelper
{
/**
* Tracing worker that handles the indirect/delegated method call and
* and logs when the call is made (at the FINER logging level) and logs
* parameters, return values and an elapsed time in milliseconds (at
* the FINEST logging level).
*
* @param proxy
* The object upon which the method is invoked.
* @param args
* Arguments, if any, to <code>method</code>.
* @param logger
* The output target for the trace data.
* @param caller
* A text description of the calling method class and name
* for insertion into each log entry.
*
* @return The called method's return value or <code>null</code> if
* there is no return value. Note that this design does not
* allow the caller to determine the difference between a
* <code>void</code> return and a return of a genuine
* <code>null</code>.
*
* @throws Throwable
* If the called method generates any exception or error.
*/
public static Object trace(Invocable proxy,
Object[] args,
CentralLogger logger,
String caller)
throws Throwable
{
String proxyDetails = proxy.describe();
boolean doLogging = !proxyDetails.contains(CentralLogService.class.getSimpleName());
long millis = 0;
if (doLogging && logger.isLoggable(Level.FINER))
{
logger.logp(Level.FINER,
caller,
"",
proxy.describe());
if (logger.isLoggable(Level.FINEST))
{
if (args != null && args.length > 0)
{
StringBuilder parms = new StringBuilder("parameters (");
expandParameters(args, parms);
parms.append(')');
logger.logp(Level.FINEST,
caller,
"",
parms.toString());
}
millis = System.currentTimeMillis();
}
}
Object result = null;
try
{
result = proxy.invoke(args);
}
catch (Throwable th)
{
result = th;
throw th;
}
finally
{
if (doLogging && logger.isLoggable(Level.FINEST))
{
// calc elapsed time
millis = System.currentTimeMillis() - millis;
if (result != null)
{
StringBuilder sb = new StringBuilder("result = ");
render(result, sb);
logger.logp(Level.FINEST,
caller,
"",
sb.toString());
}
String msg = CentralLogger.generate("elapsed millis = %d", millis);
logger.logp(Level.FINEST, caller, "", msg);
}
}
return result;
}
/**
* Render the array of method arguments into a text form, optionally
* using recursion to emit elements that are themselves arrays.
*
* @param args
* The method arguments passed to the invocation mechanism.
* @param buf
* The output buffer. Must not be <code>null</code>.
*/
public static void expandParameters(Object[] args, StringBuilder buf)
{
for (int i = 0; i < args.length; i++)
{
if (i != 0)
{
buf.append(", ");
}
render(args[i], buf);
}
}
/**
* Render the the given object into a text form including handling
* arrays.
*
* @param arg
* The object to render as text.
* @param buf
* The output buffer. Must not be <code>null</code>.
*/
public static void render(Object arg, StringBuilder buf)
{
if (arg == null)
{
buf.append("null");
}
else if (arg instanceof BaseDataType)
{
// BDT needs a different form otherwise the output may be
// unexpected (e.g. character types would be truncated to
// length 8)
buf.append(((BaseDataType) arg).toStringMessage());
}
else if (arg instanceof Object[])
{
// use recursion to dump the contained element that is itself
// an array
buf.append('[');
expandParameters((Object[]) arg, buf);
buf.append(']');
}
else if (arg.getClass().isArray())
{
// must be an array of primitives
StringHelper.render(arg, buf);
}
else
{
// common case
buf.append(arg.toString());
}
}
}