/*
* Copyright 2014-2015 JKOOL, LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jkoolcloud.tnt4j.dump;
import com.jkoolcloud.tnt4j.core.Property;
import com.jkoolcloud.tnt4j.core.UsecTimestamp;
import com.jkoolcloud.tnt4j.utils.TimeService;
import com.jkoolcloud.tnt4j.utils.Utils;
/**
* <p>
* This class implements a default dump formatter. Dumps are formatted as follows using JSON.
*
* <pre>
* <code>
* {
* "dump.status": "START",
* "server.name": "XOMEGA",
* "server.address": "ip-address",
* "vm.name": "123036@server",
* "vm.pid": 123036,
* "dump.sink": "com.jkoolcloud.tnt4j.dump.FileDumpSink@45d64c37{file: .\123036@server.dump, append: true, is.open: true}",
* "dump.time.string": "<time-stamp-string>"
* }
* {
* "dump.reason": "java.lang.Exception: VM-Shutdown"
* "dump.name": "runtimeMetrics",
* "dump.provider": "com.nastel.TradeApp",
* "dump.category": "ApplRuntime",
* "dump.time.string": "<time-stamp-string>",
* "dump.time.stamp": 1394115455190,
* "dump.snapshot": {
* ....
* }
* "dump.elapsed.ms=": 4
* }
* .... (next dump)
* .... (next dump)
* .... (next dump)
* {
* "dump.status": "END",
* "server.name": "XOMEGA",
* "server.address": "ip-address",
* "vm.name": "123036@server",
* "vm.pid": 123036,
* "dump.sink": "com.jkoolcloud.tnt4j.dump.FileDumpSink@45d64c37{file: .\123036@server.dump, append: true, is.open: true}",
* "dump.time.string": "<time-stamp-string>"
* "dump.elapsed.ms=": 1334
* }
* </code>
* </pre>
* </p>
*
*
* @version $Revision: 10 $
*
* @see DumpSink
* @see DumpFormatter
* @see DumpCollection
*/
public class DefaultDumpFormatter implements DumpFormatter {
private static ThreadLocal<Long> TIME_TABLE = new ThreadLocal<Long>();
private static final String INDENT = "\t";
private static final String NEWLINE = "\n";
private static final String END_ATTR = ",\n";
private String _format(DumpCollection dump, String padding) {
StringBuilder buffer = new StringBuilder(1024);
buffer.append(padding).append(Utils.quote("dump.name")).append(": ").append(Utils.quote(dump.getName())).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.category")).append(": ").append(Utils.quote(dump.getCategory())).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.provider")).append(": ").append(Utils.quote(dump.getDumpProvider().getProviderName())).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.provider.category")).append(": ").append(Utils.quote(dump.getDumpProvider().getCategoryName())).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.time.string")).append(": ").append(Utils.quote(UsecTimestamp.getTimeStamp(dump.getTime(),0))).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.time.stamp")).append(": ").append(dump.getTime()).append(END_ATTR);
buffer.append(padding).append(Utils.quote("dump.snapshot")).append(": {\n");
int startLen = buffer.length();
String subPadding = padding + INDENT;
for (Property entry : dump.getSnapshot()) {
if (buffer.length() > startLen) {
buffer.append(END_ATTR);
}
Object value = entry.getValue();
if (value instanceof DumpCollection) {
buffer.append(subPadding).append(Utils.quote("dump.collection")).append(": {\n");
buffer.append(_format((DumpCollection)value, subPadding + INDENT));
buffer.append(NEWLINE).append(subPadding).append("}");
} else if (value instanceof Number) {
buffer.append(subPadding).append(Utils.quote(entry.getKey())).append(": ").append(value);
} else {
buffer.append(subPadding).append(Utils.quote(entry.getKey())).append(": ").append(Utils.quote(value));
}
}
buffer.append(NEWLINE).append(padding).append("}");
return buffer.toString();
}
@Override
public String format(DumpCollection dump) {
return _format(dump, "");
}
@Override
public String format(Object obj, Object...args) {
return Utils.format(String.valueOf(obj), args);
}
@Override
public String getHeader(DumpCollection dump) {
StringBuilder buffer = new StringBuilder(1024);
Throwable reason = dump.getReason();
buffer.append("{\n");
buffer.append(Utils.quote("dump.reason")).append(": ").append(Utils.quote(reason));
if (reason != null) {
StackTraceElement[] stack = reason.getStackTrace();
for (int i=0; i < stack.length; i++) {
buffer.append(NEWLINE).append(Utils.quote("stack.frame[" + i + "]")).append(": ").append(Utils.quote(stack[i]));
}
}
return buffer.toString();
}
@Override
public String getFooter(DumpCollection dump) {
StringBuilder buffer = new StringBuilder(1024);
buffer.append(Utils.quote("dump.elapsed.ms")).append(": ").append((TimeService.currentTimeMillis() - dump.getTime()));
buffer.append("\n}");
return buffer.toString();
}
@Override
public String getCloseStanza(DumpSink sink) {
StringBuilder buffer = new StringBuilder(1024);
buffer.append("{\n");
buffer.append(Utils.quote("dump.status")).append(": ").append(Utils.quote("END")).append(END_ATTR);
buffer.append(Utils.quote("server.name")).append(": ").append(Utils.quote(Utils.getLocalHostName())).append(END_ATTR);
buffer.append(Utils.quote("server.address")).append(": ").append(Utils.quote(Utils.getLocalHostAddress())).append(END_ATTR);
buffer.append(Utils.quote("vm.name")).append(": ").append(Utils.quote(Utils.getVMName())).append(END_ATTR);
buffer.append(Utils.quote("vm.pid")).append(": ").append(Utils.getVMPID()).append(END_ATTR);
buffer.append(Utils.quote("dump.sink")).append(": ").append(Utils.quote(sink)).append(END_ATTR);
buffer.append(Utils.quote("dump.time.string")).append(": ").append(Utils.quote(UsecTimestamp.getTimeStamp())).append(END_ATTR);
long elapsed_ms = TimeService.currentTimeMillis() - TIME_TABLE.get();
buffer.append(Utils.quote("dump.elapsed.ms")).append(": ").append(elapsed_ms);
buffer.append("\n}");
return buffer.toString();
}
@Override
public String getOpenStanza(DumpSink sink) {
StringBuilder buffer = new StringBuilder(1024);
TIME_TABLE.set(TimeService.currentTimeMillis());
buffer.append("{\n");
buffer.append(Utils.quote("dump.status")).append(": ").append(Utils.quote("START")).append(END_ATTR);
buffer.append(Utils.quote("server.name")).append(": ").append(Utils.quote(Utils.getLocalHostName())).append(END_ATTR);
buffer.append(Utils.quote("server.address")).append(": ").append(Utils.quote(Utils.getLocalHostAddress())).append(END_ATTR);
buffer.append(Utils.quote("vm.name")).append(": ").append(Utils.quote(Utils.getVMName())).append(END_ATTR);
buffer.append(Utils.quote("vm.pid")).append(": ").append(Utils.getVMPID()).append(END_ATTR);
buffer.append(Utils.quote("dump.sink")).append(": ").append(Utils.quote(sink)).append(END_ATTR);
buffer.append(Utils.quote("dump.time.string")).append(": ").append(Utils.quote(UsecTimestamp.getTimeStamp()));
buffer.append("\n}");
return buffer.toString();
}
}