001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.logging;
006:
007: import com.tc.logging.CustomerLogging;
008: import com.tc.logging.TCLogger;
009: import com.tc.logging.TCLogging;
010: import com.tc.object.TCObject;
011: import com.tc.object.bytecode.ByteCodeUtil;
012: import com.tc.object.config.DSOClientConfigHelper;
013: import com.tc.object.lockmanager.api.LockLevel;
014: import com.tc.object.tx.WaitInvocation;
015: import com.tc.util.Util;
016:
017: public class RuntimeLoggerImpl implements RuntimeLogger {
018: private static final TCLogger internalLogger = TCLogging
019: .getLogger(RuntimeLoggerImpl.class);
020:
021: private final TCLogger logger;
022:
023: private final boolean lockDebug;
024: private final boolean fieldChangeDebug;
025: private final boolean arrayChangeDebug;
026: private final boolean newManagedObjectDebug;
027: private final boolean distributedMethodDebug;
028: private final boolean nonPortableDump;
029: private final boolean waitNotifyDebug;
030:
031: private final boolean fullStack;
032: private final boolean caller;
033: private final boolean autoLockDetails;
034:
035: public RuntimeLoggerImpl(DSOClientConfigHelper configHelper) {
036: this .logger = CustomerLogging.getDSORuntimeLogger();
037:
038: // runtime logging items
039: this .lockDebug = configHelper.runtimeLoggingOptions()
040: .logLockDebug().getBoolean();
041: this .fieldChangeDebug = configHelper.runtimeLoggingOptions()
042: .logFieldChangeDebug().getBoolean();
043: this .arrayChangeDebug = fieldChangeDebug;
044: this .newManagedObjectDebug = configHelper
045: .runtimeLoggingOptions().logNewObjectDebug()
046: .getBoolean();
047: this .distributedMethodDebug = configHelper
048: .runtimeLoggingOptions().logDistributedMethodDebug()
049: .getBoolean();
050: this .nonPortableDump = configHelper.runtimeLoggingOptions()
051: .logNonPortableDump().getBoolean();
052: this .waitNotifyDebug = configHelper.runtimeLoggingOptions()
053: .logWaitNotifyDebug().getBoolean();
054:
055: // runtime logging options
056: this .caller = configHelper.runtimeOutputOptions().doCaller()
057: .getBoolean();
058: this .fullStack = configHelper.runtimeOutputOptions()
059: .doFullStack().getBoolean();
060: this .autoLockDetails = configHelper.runtimeOutputOptions()
061: .doAutoLockDetails().getBoolean();
062: }
063:
064: public boolean lockDebug() {
065: return this .lockDebug;
066: }
067:
068: public boolean fieldChangeDebug() {
069: return this .fieldChangeDebug;
070: }
071:
072: public boolean arrayChangeDebug() {
073: return this .arrayChangeDebug;
074: }
075:
076: public boolean newManagedObjectDebug() {
077: return this .newManagedObjectDebug;
078: }
079:
080: public boolean waitNotifyDebug() {
081: return this .waitNotifyDebug;
082: }
083:
084: public boolean distributedMethodDebug() {
085: return this .distributedMethodDebug;
086: }
087:
088: public boolean nonPortableDump() {
089: return this .nonPortableDump;
090: }
091:
092: public void lockAcquired(String lockName, int level,
093: Object instance, TCObject tcObject) {
094: boolean isAutoLock = ByteCodeUtil.isAutolockName(lockName);
095:
096: if (isAutoLock) {
097: autoLockAcquired(lockName, level, instance, tcObject);
098: } else {
099: namedLockAcquired(lockName, level);
100: }
101: }
102:
103: private void namedLockAcquired(String lockName, int level) {
104: StringBuffer message = new StringBuffer("Named lock [").append(
105: lockName).append("] acquired with level ").append(
106: LockLevel.toString(level));
107: appendCall(message);
108: logger.info(message);
109: }
110:
111: private void autoLockAcquired(String lockName, int level,
112: Object instance, TCObject tcObject) {
113: StringBuffer message = new StringBuffer("Autolock [").append(
114: lockName).append("] acquired with level ").append(
115: LockLevel.toString(level));
116:
117: if (autoLockDetails && (instance != null)) {
118: message.append("\n type: ").append(
119: instance.getClass().getName());
120: message.append(", identityHashCode: 0x").append(
121: Integer.toHexString(System
122: .identityHashCode(instance)));
123: }
124:
125: appendCall(message);
126:
127: logger.info(message);
128: }
129:
130: private void appendCall(StringBuffer message) {
131: if (fullStack || caller) {
132: StackTraceElement[] stack = getTrimmedStack();
133: if (stack != null) {
134: message.append("\n");
135: if (fullStack) {
136: for (int i = 0; i < stack.length; i++) {
137: message.append(" at ").append(
138: stack[i].toString());
139:
140: if (i < (stack.length - 1)) {
141: message.append("\n");
142: }
143: }
144: } else {
145: message.append(" call: ").append(
146: stack[0].toString());
147: }
148: }
149: }
150:
151: }
152:
153: public void literalValueChanged(TCObject source, Object newValue) {
154: StringBuffer message = new StringBuffer(
155: "DSO object literal value changed\n");
156: if (newValue != null) {
157: message.append("\n newValue type: ").append(
158: newValue.getClass().getName());
159: message.append(", identityHashCode: 0x").append(
160: Integer.toHexString(System
161: .identityHashCode(newValue)));
162: } else {
163: message.append("\n newValue: null");
164: }
165:
166: logger.info(message.toString());
167: }
168:
169: public void fieldChanged(TCObject source, String classname,
170: String fieldName, Object newValue, int index) {
171: StringBuffer message = new StringBuffer(
172: "DSO object field changed\n");
173: message.append(" class: ").append(classname).append(
174: ", field: ").append(fieldName);
175: if (index >= 0) {
176: message.append(", index: ").append(index);
177: }
178: if (newValue != null) {
179: message.append("\n newValue type: ").append(
180: newValue.getClass().getName());
181: message.append(", identityHashCode: 0x").append(
182: Integer.toHexString(System
183: .identityHashCode(newValue)));
184: } else {
185: message.append("\n newValue: null");
186: }
187:
188: logger.info(message.toString());
189: }
190:
191: public void arrayChanged(TCObject source, int startPos, Object array) {
192: StringBuffer message = new StringBuffer("DSO array changed\n");
193: message.append("\n startPos: ").append(startPos);
194: message.append("\n subset component types: \n").append(
195: array.getClass().getComponentType());
196:
197: logger.info(message.toString());
198: }
199:
200: public void newManagedObject(TCObject object) {
201: StringBuffer message = new StringBuffer(
202: "New DSO Object instance created\n");
203: message.append(" instance: ").append(
204: baseToString(object.getPeerObject())).append("\n");
205: message.append(" object ID: ").append(object.getObjectID());
206: appendCall(message);
207: logger.info(message.toString());
208: }
209:
210: public void objectNotify(boolean all, Object obj, TCObject tcObject) {
211: StringBuffer message = new StringBuffer("notify")
212: .append(all ? "All()" : "()");
213: message.append(" called on ").append(baseToString(obj)).append(
214: ", ObjectID: ").append(tcObject.getObjectID().toLong());
215: logger.info(message.toString());
216: }
217:
218: public void objectWait(WaitInvocation call, Object obj,
219: TCObject tcObject) {
220: StringBuffer message = new StringBuffer(call.toString())
221: .append(" called on ");
222: message.append(baseToString(obj)).append(", ObjectID: ")
223: .append(tcObject.getObjectID().toLong());
224: logger.info(message.toString());
225: }
226:
227: public void distributedMethodCall(String receiverName,
228: String methodName, String params) {
229: StringBuffer message = new StringBuffer(
230: "Distributed method invoked\n");
231: message.append(" receiver class: ").append(receiverName)
232: .append("\n");
233: message.append(" methodName: ").append(methodName)
234: .append("\n");
235: message.append(" params: ").append(params).append("\n");
236:
237: appendCall(message);
238: logger.info(message.toString());
239: }
240:
241: public void distributedMethodCallError(String receiverClassName,
242: String methodName, String params, Throwable error) {
243: StringBuffer message = new StringBuffer(
244: "Unhandled execption occurred in distributed method call\n");
245: message.append(" receiver class: ").append(receiverClassName)
246: .append("\n");
247: message.append(" methodName: ").append(methodName).append("\n");
248: message.append(" params: ").append(params).append("\n");
249:
250: logger.warn(message.toString(), error);
251: }
252:
253: private static String baseToString(Object obj) {
254: if (obj == null) {
255: return null;
256: }
257: return obj.getClass().getName() + "@"
258: + Integer.toHexString(System.identityHashCode(obj));
259: }
260:
261: private static StackTraceElement[] getTrimmedStack() {
262: StackTraceElement[] stack = new Throwable().getStackTrace();
263: if ((stack == null) || (stack.length <= 1)) {
264: internalLogger.warn("funny stack returned: "
265: + Util.enumerateArray(stack));
266: return null;
267: }
268:
269: int index = 0;
270: while (index < stack.length) {
271: String className = stack[index].getClassName();
272:
273: if (className.equals("com.tc.object.bytecode.ManagerUtil")) {
274: break;
275: }
276:
277: index++;
278: }
279:
280: // advance to the calling frame
281: index++;
282:
283: if (index < (stack.length - 1)) {
284: StackTraceElement[] rv = new StackTraceElement[stack.length
285: - index];
286: System.arraycopy(stack, index, rv, 0, rv.length);
287: return rv;
288: } else {
289: internalLogger.warn("could not find proper stack frame: "
290: + Util.enumerateArray(stack));
291: return null;
292: }
293:
294: // unreachable
295: }
296:
297: }
|