/******************************************************************************* * Copyright (c) 2012, 2014 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Francois Chouinard - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.internal.tmf.core; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import org.eclipse.core.runtime.Platform; import org.eclipse.tracecompass.tmf.core.component.ITmfEventProvider; import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest; import org.eclipse.tracecompass.tmf.core.signal.TmfSignal; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; /** * The TMF Core tracer, used to trace TMF internal components. * <p> * The tracing classes are independently controlled (i.e no implicit inclusion) * from the launch configuration's Tracing. The resulting trace is stored in a * distinct file (TmfTrace.log) in a format that can later be analyzed by TMF. * <p> * The tracing classes are: * <ul> * <li><strong>Component</strong>: TMF components life-cycle * <li><strong>Request</strong>: TMF requests life-cycle * <li><strong>Signal</strong>: TMF signals triggering and distribution * <li><strong>Event</strong>: TMF trace events * <li><strong>Analysis</strong>: TMF analyzes * </ul> * * @version 1.0 * @author Francois Chouinard */ @SuppressWarnings("nls") public final class TmfCoreTracer { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ private static final String PLUGIN_ID = Activator.PLUGIN_ID; // Tracing keys (in .options) private static final String COMPONENT_TRACE_KEY = PLUGIN_ID + "/component"; private static final String REQUEST_TRACE_KEY = PLUGIN_ID + "/request"; private static final String SIGNAL_TRACE_KEY = PLUGIN_ID + "/signal"; private static final String EVENT_TRACE_KEY = PLUGIN_ID + "/event"; private static final String ANALYSIS_TRACE_KEY = PLUGIN_ID + "/analysis"; private static final String INDEXER_TRACE_KEY = PLUGIN_ID + "/indexer"; private static final String TRACE_FILE_NAME = "TmfTrace.log"; // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ // Classes tracing flags private static volatile boolean fComponentClassEnabled = false; private static volatile boolean fRequestClassEnabled = false; private static volatile boolean fSignalClassEnabled = false; private static volatile boolean fEventClassEnabled = false; private static volatile boolean fAnalysisClassEnabled = false; private static volatile boolean fIndexerClassEnabled = false; // Trace log file private static BufferedWriter fTraceFile; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Constructor */ private TmfCoreTracer() { // Do nothing } // ------------------------------------------------------------------------ // Start/stop tracing - controlled by the plug-in // ------------------------------------------------------------------------ /** * Set the tracing flags according to the launch configuration */ public static synchronized void init() { String traceKey; boolean isTracing = false; traceKey = Platform.getDebugOption(COMPONENT_TRACE_KEY); if (traceKey != null) { fComponentClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fComponentClassEnabled; } traceKey = Platform.getDebugOption(REQUEST_TRACE_KEY); if (traceKey != null) { fRequestClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fRequestClassEnabled; } traceKey = Platform.getDebugOption(SIGNAL_TRACE_KEY); if (traceKey != null) { fSignalClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fSignalClassEnabled; } traceKey = Platform.getDebugOption(EVENT_TRACE_KEY); if (traceKey != null) { fEventClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fEventClassEnabled; } traceKey = Platform.getDebugOption(ANALYSIS_TRACE_KEY); if (traceKey != null) { fAnalysisClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fAnalysisClassEnabled; } traceKey = Platform.getDebugOption(INDEXER_TRACE_KEY); if (traceKey != null) { fIndexerClassEnabled = Boolean.parseBoolean(traceKey); isTracing |= fIndexerClassEnabled; } // Create trace log file if any of the flags was set if (isTracing) { try { fTraceFile = new BufferedWriter(new FileWriter(TRACE_FILE_NAME)); } catch (IOException e) { Activator.logError("Error opening log file " + TRACE_FILE_NAME, e); fTraceFile = null; } } } /** * Close the trace log file */ public static synchronized void stop() { if (fTraceFile != null) { try { fTraceFile.close(); fTraceFile = null; } catch (IOException e) { Activator.logError("Error closing log file", e); } } } // ------------------------------------------------------------------------ // Predicates // ------------------------------------------------------------------------ /** * Is component tracing enabled? * * @return true if components are traced, false otherwise */ public static boolean isComponentTraced() { return fComponentClassEnabled; } /** * Is request tracing enabled? (useful to debug scheduling issues) * * @return true if requests are traced, false otherwise */ public static boolean isRequestTraced() { return fRequestClassEnabled; } /** * Is signal tracing enabled? (useful to debug UI issues) * * @return true if signals are traced, false otherwise */ public static boolean isSignalTraced() { return fSignalClassEnabled; } /** * Is event tracing enabled? (useful to debug parser issues) * * @return true if events are traced, false otherwise */ public static boolean isEventTraced() { return fEventClassEnabled; } /** * Is analysis tracing enabled? (useful to debug analysis issues) * * @return true if analyses are traced, false otherwise */ public static boolean isAnalysisTraced() { return fAnalysisClassEnabled; } /** * Is indexer tracing enabled? (useful to debug indexer issues) * * @return true if indexer is traced, false otherwise */ public static boolean isIndexerTraced() { return fAnalysisClassEnabled; } // ------------------------------------------------------------------------ // Tracing methods // ------------------------------------------------------------------------ /** * The central tracing method. Prepends the timestamp and the thread id to * the trace message. * * @param msg * the trace message to log */ public static synchronized void trace(String msg) { // Leave when there is no place to write the message. if (fTraceFile == null) { return; } // Set the timestamp (ms resolution) long currentTime = System.currentTimeMillis(); StringBuilder message = new StringBuilder("["); message.append(currentTime / 1000); message.append("."); message.append(String.format("%1$03d", currentTime % 1000)); message.append("] "); // Set the thread id message.append("[TID="); message.append(String.format("%1$03d", Thread.currentThread().getId())); message.append("] "); // Append the trace message message.append(msg); System.out.println(message); // Write to file try { fTraceFile.write(message.toString()); fTraceFile.newLine(); fTraceFile.flush(); } catch (IOException e) { Activator.logError("Error writing to log file", e); } } // ------------------------------------------------------------------------ // TMF Core specific trace formatters // ------------------------------------------------------------------------ /** * Trace an event happening in a component. * * @param componentName * The name of the component being traced * @param msg * The message to record for this component */ public static void traceComponent(String componentName, String msg) { if (fComponentClassEnabled) { String message = ("[CMP] Cmp=" + componentName + " " + msg); trace(message); } } /** * Trace an event happening in an event request. * * @param requestId * The request ID of the request being traced * @param msg * The message to record for this component */ public static void traceRequest(int requestId, String msg) { if (fRequestClassEnabled) { String message = ("[REQ] Req=" + requestId + " " + msg); trace(message); } } /** * Trace an event happening in an indexer. * * @param msg * The message to record for this indexer */ public static void traceIndexer(String msg) { if (fIndexerClassEnabled) { String message = ("[INDEXER] " + msg); trace(message); } } /** * Trace a signal being fired * * @param signal * The signal * @param msg * The message to record for this component */ public static void traceSignal(TmfSignal signal, String msg) { if (fSignalClassEnabled) { String message = ("[SIG] Sig=" + signal.getClass().getSimpleName() + " Target=" + msg); trace(message); } } /** * Trace an event with its provider and request * * @param provider * The provider supplying the event * @param request * The request being traced * @param event * The event being traced */ public static void traceEvent(ITmfEventProvider provider, ITmfEventRequest request, ITmfEvent event) { if (fEventClassEnabled) { String message = ("[EVT] Provider=" + provider.toString() + ", Req=" + request.getRequestId() + ", Event=" + event.getTimestamp()); trace(message); } } /** * Trace an event happening in an analysis * * @param analysisId * The analysis ID of the analysis being run * @param trace * The trace this analysis is run on * @param msg * The message to record for this analysis */ public static void traceAnalysis(String analysisId, ITmfTrace trace, String msg) { if (fAnalysisClassEnabled) { String traceName = (trace == null) ? "" : trace.getName(); String message = ("[ANL] Anl=" + analysisId + " for " + traceName + " " + msg); trace(message); } } }