trace/traceviewer/com.nokia.traceviewer/src/com/nokia/traceviewer/engine/dataprocessor/Logger.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Wed, 23 Jun 2010 14:49:59 +0300
changeset 11 5b9d4d8641ce
permissions -rw-r--r--
TraceViewer 2.6.0

/*
 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description:
 *
 * Logger DataProcessor
 *
 */
package com.nokia.traceviewer.engine.dataprocessor;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import com.nokia.traceviewer.action.TraceViewerActionUtils;
import com.nokia.traceviewer.engine.TraceProperties;
import com.nokia.traceviewer.engine.TraceViewerGlobals;
import com.nokia.traceviewer.engine.TraceViewerUtils;

/**
 * Logger DataProcessor
 * 
 */
public final class Logger implements DataProcessor {

	/**
	 * Equals char
	 */
	private static final char EQUALS_CHAR = '=';

	/**
	 * Parameter char
	 */
	private static final char PARAMETER_CHAR = 'p';

	/**
	 * Machine readable time tag
	 */
	private static final String TAG_TIME = "time="; //$NON-NLS-1$

	/**
	 * Machine readable CPU ID tag
	 */
	private static final String TAG_CPU_ID = "cpuID="; //$NON-NLS-1$

	/**
	 * Machine readable Thread ID tag
	 */
	private static final String TAG_THREAD_ID = "threadID="; //$NON-NLS-1$

	/**
	 * Component ID tag
	 */
	private static final String TAG_COMPONENT_ID = "compID="; //$NON-NLS-1$

	/**
	 * Group ID tag
	 */
	private static final String TAG_GROUP_ID = "groupID="; //$NON-NLS-1$

	/**
	 * Trace ID tag
	 */
	private static final String TAG_TRACE_ID = "traceID="; //$NON-NLS-1$

	/**
	 * Trace text tag
	 */
	private static final String TAG_TRACE_TEXT = "trace="; //$NON-NLS-1$

	/**
	 * Data tag
	 */
	private static final String DATA_TAG = "data="; //$NON-NLS-1$

	/**
	 * Comment tag
	 */
	private static final String COMMENT_TAG = "comment="; //$NON-NLS-1$

	/**
	 * Empty string
	 */
	private static final String EMPTY = ""; //$NON-NLS-1$

	/**
	 * Start bracket tag
	 */
	private static final char TAG_START_BRACKET = '[';

	/**
	 * End bracket tag
	 */
	private static final char TAG_END_BRACKET = ']';

	/**
	 * Hyphen char
	 */
	private static final char HYPHEN_CHAR = '-';

	/**
	 * Underscore char
	 */
	private static final char UNDERSCORE_CHAR = '_';

	/**
	 * Semicolon char
	 */
	private static final char SEMICOLON_CHAR = ';';

	/**
	 * End line character \r
	 */
	private static final char ENDLINE_R = '\r';

	/**
	 * End line character \n
	 */
	private static final char ENDLINE_N = '\n';

	/**
	 * Tabulator character
	 */
	private static final char TABULATOR = '\t';

	/**
	 * Writer to be used for writing
	 */
	private PrintWriter plainOutput;

	/**
	 * Filechannel where binary log is written
	 */
	private FileChannel binaryOutput;

	/**
	 * Logging in plain text
	 */
	private boolean plainLogging;

	/**
	 * Logging in binary
	 */
	private boolean binaryLogging;

	/**
	 * Path to plain text log file
	 */
	private String plainLogPath;

	/**
	 * Path to binary log file
	 */
	private String binaryLogPath;

	/**
	 * Omitting timestamp or not
	 */
	private boolean omitTimestamps;

	/**
	 * Machine readable log file
	 */
	private boolean machineReadable;

	/**
	 * Tells if a log file is opened
	 */
	private boolean logFileOpened;

	/**
	 * Opened log file path
	 */
	private String openedLogFilePath;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.nokia.traceviewer.engine.DataProcessor#processData(com.nokia.traceviewer
	 * .engine.TraceProperties)
	 */
	public void processData(TraceProperties properties) {
		if (!properties.traceConfiguration.isFilteredOut()
				&& !properties.traceConfiguration.isScrolledTrace()
				&& !properties.traceConfiguration.isTriggeredOut()) {

			// Logging as plain text
			if (plainLogging) {

				String trace = createPlainTextTrace(properties);

				// Write the trace
				if (trace != null) {
					plainOutput.write(trace);
				}
			}

			// Binary logging
			if (binaryLogging) {
				try {
					if (properties.byteBuffer != null && binaryOutput != null) {

						// Write all parts of multipart trace
						if (properties.bTraceInformation
								.getMultiPartTraceParts() != null) {
							Iterator<byte[]> i = properties.bTraceInformation
									.getMultiPartTraceParts().getTraceParts()
									.iterator();

							while (i.hasNext()) {
								byte[] byteArr = i.next();
								binaryOutput.write(ByteBuffer.wrap(byteArr));
							}
						} else {

							// Write the message to file
							int position = properties.byteBuffer.position();
							int limit = properties.byteBuffer.limit();
							properties.byteBuffer.limit(properties.messageStart
									+ properties.messageLength);
							properties.byteBuffer
									.position(properties.messageStart);

							binaryOutput.write(properties.byteBuffer);
							properties.byteBuffer.limit(limit);
							properties.byteBuffer.position(position);
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * Create plain text trace
	 * 
	 * @param properties
	 *            trace properties
	 * @return plain text trace string or null if this trace should not be
	 *         logged
	 */
	private String createPlainTextTrace(TraceProperties properties) {
		String ret = null;
		StringBuffer trace = null;

		// Normal ASCII trace log
		if (!machineReadable && !properties.binaryTrace) {

			// If omitting timestamps, don't write them
			if (omitTimestamps || properties.timestampString == null) {
				int traceLen = properties.traceString.length() + 1;
				trace = new StringBuffer(traceLen);
				if (properties.bTraceInformation.isTraceMissing()) {
					trace.append(TraceViewerActionUtils.TRACES_DROPPED_MSG);
				}
				trace.append(properties.traceString);
				trace.append(ENDLINE_N);

				// Write timestamp
			} else {
				StringBuffer timeFromPreviousSB = TraceViewerGlobals
						.getTraceViewer().getDataProcessorAccess()
						.getTimestampParser().getTimeFromPreviousString(
								properties.timeFromPreviousTrace);
				int traceLen = properties.timestampString.length() + 1
						+ timeFromPreviousSB.length()
						+ properties.traceString.length() + 1;
				trace = new StringBuffer(traceLen);
				if (properties.bTraceInformation.isTraceMissing()) {
					trace.append(TraceViewerActionUtils.TRACES_DROPPED_MSG);
				}
				trace.append(properties.timestampString);
				trace.append(timeFromPreviousSB);
				trace.append(TABULATOR);
				trace.append(properties.traceString);
				trace.append(ENDLINE_N);
			}

			// Machine readable log file
		} else if (machineReadable) {

			// Create buffer three times as big as original trace text
			if (properties.traceString != null) {
				trace = new StringBuffer(properties.traceString.length() * 3);
			} else {
				trace = new StringBuffer();
			}

			// Get trace variables
			int cid = properties.information.getComponentId();
			int gid = properties.information.getGroupId();
			int tid = properties.information.getTraceId();

			// Timestamp
			trace.append(TAG_TIME);
			if (properties.timestampString != null) {
				trace.append(properties.timestampString);
			} else {
				trace.append(properties.timestamp);
			}
			trace.append(SEMICOLON_CHAR);

			// CPU ID
			trace.append(TAG_CPU_ID);
			if (properties.bTraceInformation.getCpuId() != -1) {
				trace.append(properties.bTraceInformation.getCpuId());
			} else {
				trace.append(HYPHEN_CHAR);
			}
			trace.append(SEMICOLON_CHAR);

			// Thread ID
			trace.append(TAG_THREAD_ID);
			if (properties.bTraceInformation.getThreadId() != 0) {
				trace.append(properties.bTraceInformation.getThreadId());
			} else {
				trace.append(HYPHEN_CHAR);
			}
			trace.append(SEMICOLON_CHAR);

			// Get Component, Group and Trace names
			String[] names = TraceViewerGlobals.getDecodeProvider()
					.getComponentGroupTraceName(cid, gid, tid);

			// Component ID
			String componentName = names[0];
			if (componentName == null) {
				componentName = EMPTY;
			}
			trace.append(TAG_COMPONENT_ID);
			trace
					.append(componentName.replace(SEMICOLON_CHAR,
							UNDERSCORE_CHAR));
			trace.append(TAG_START_BRACKET);
			trace.append(cid);
			trace.append(TAG_END_BRACKET);
			trace.append(SEMICOLON_CHAR);

			// Group ID
			String groupName = names[1];
			if (groupName == null) {
				groupName = EMPTY;
			}
			trace.append(TAG_GROUP_ID);
			trace.append(groupName.replace(SEMICOLON_CHAR, UNDERSCORE_CHAR));
			trace.append(TAG_START_BRACKET);
			trace.append(gid);
			trace.append(TAG_END_BRACKET);
			trace.append(SEMICOLON_CHAR);

			// Trace ID
			String traceName = names[2];
			if (traceName == null) {
				traceName = EMPTY;
			}
			trace.append(TAG_TRACE_ID);
			trace.append(traceName.replace(SEMICOLON_CHAR, UNDERSCORE_CHAR));
			trace.append(TAG_START_BRACKET);
			trace.append(tid);
			trace.append(TAG_END_BRACKET);
			trace.append(SEMICOLON_CHAR);

			// Parameters
			for (int i = 0; i < properties.parameters.size(); i++) {
				trace.append(PARAMETER_CHAR);
				trace.append(i + 1);
				trace.append(EQUALS_CHAR);
				trace.append(properties.parameters.get(i).replace(
						SEMICOLON_CHAR, UNDERSCORE_CHAR));
				trace.append(SEMICOLON_CHAR);
			}

			// Trace comment
			if (properties.traceComment != null) {
				trace.append(COMMENT_TAG);
				trace.append(properties.traceComment);
				trace.append(SEMICOLON_CHAR);
			}

			// Trace string
			if (properties.traceString != null) {
				trace.append(TAG_TRACE_TEXT);
				trace.append(properties.traceString.replace(SEMICOLON_CHAR,
						UNDERSCORE_CHAR));
				trace.append(SEMICOLON_CHAR);
				// Trace as hex
			} else {
				// Get data as hex
				String hexTrace = TraceViewerUtils.getTraceAsHexString(
						properties.byteBuffer, properties.dataStart,
						properties.dataLength, false);
				trace.append(DATA_TAG);
				trace.append(hexTrace);
				trace.append(SEMICOLON_CHAR);

			}

			trace.append(ENDLINE_R);
			trace.append(ENDLINE_N);
		}

		if (trace != null) {
			ret = trace.toString();
		}

		return ret;
	}

	/**
	 * Constructor
	 */
	public Logger() {
		plainLogging = false;
		binaryLogging = false;
		omitTimestamps = false;
		plainLogPath = EMPTY;
		binaryLogPath = EMPTY;
	}

	/**
	 * Flushes data
	 */
	public void flush() {
		if (plainOutput != null) {
			plainOutput.flush();
		}
	}

	/**
	 * Gets plain text logging status
	 * 
	 * @return status of plain text logging
	 */
	public boolean isPlainLogging() {
		return plainLogging;
	}

	/**
	 * Gets plain text log file path
	 * 
	 * @return plainLogPath
	 */
	public String getPlainLogPath() {
		return plainLogPath;
	}

	/**
	 * Gets binary log file path
	 * 
	 * @return binaryLogPath
	 */
	public String getBinaryLogPath() {
		return binaryLogPath;
	}

	/**
	 * Gets logging status
	 * 
	 * @return status of binary logging
	 */
	public boolean isBinLogging() {
		return binaryLogging;
	}

	/**
	 * Starts plain text logging
	 * 
	 * @param filename
	 *            file name where to save
	 * @param omitTimestamp
	 *            true if timestamps should be omitted
	 * @param machineReadable
	 *            true if log file should be machine readable
	 * @return status of starting of logging
	 */
	public boolean startPlainTextLogging(String filename,
			boolean omitTimestamp, boolean machineReadable) {
		plainLogPath = filename;
		this.omitTimestamps = omitTimestamp;
		this.machineReadable = machineReadable;

		// Build file channel
		boolean success = buildPlainFileWriter();
		plainLogging = true;
		return success;
	}

	/**
	 * Stops plain text logging
	 * 
	 * @return status of stopPlainTextLogging
	 */
	public boolean stopPlainTextLogging() {
		plainOutput.close();
		plainLogging = false;

		// Export possible comments
		TraceViewerGlobals.getTraceViewer().getDataProcessorAccess()
				.getTraceCommentHandler().exportTraceComments(plainLogPath);

		return true;
	}

	/**
	 * Start binary logging
	 * 
	 * @param filename
	 *            file name
	 * @return status of binary logging
	 */
	public boolean startBinaryLogging(String filename) {
		boolean success = false;
		try {
			binaryLogPath = filename;

			// Build file channel
			FileOutputStream outputFile = new FileOutputStream(binaryLogPath);

			binaryOutput = outputFile.getChannel();
			binaryLogging = true;
			success = true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return success;
	}

	/**
	 * Stops binary logging
	 * 
	 * @return status of stopBinLogging
	 */
	public boolean stopBinLogging() {
		binaryLogging = false;
		try {
			binaryOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// Export possible comments
		TraceViewerGlobals.getTraceViewer().getDataProcessorAccess()
				.getTraceCommentHandler().exportTraceComments(binaryLogPath);

		return true;
	}

	/**
	 * Opens log file
	 * 
	 * @param path
	 *            path to log file
	 * @param binary
	 *            binary file
	 */
	public void openLogFile(String path, boolean binary) {
		TraceViewerGlobals.getTraceViewer().getDataReaderAccess().openLogFile(
				path, binary);
		openedLogFilePath = path;
	}

	/**
	 * Builds the plain file writer
	 * 
	 * @return status of building plain text file
	 */
	public boolean buildPlainFileWriter() {
		boolean success = false;

		try {
			plainOutput = new PrintWriter(new FileWriter(plainLogPath));
			success = true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return success;
	}

	/**
	 * Tells if log file is opened
	 * 
	 * @return true if log file is opened
	 */
	public boolean isLogFileOpened() {
		return logFileOpened;
	}

	/**
	 * Sets the log file opened variable
	 * 
	 * @param logFileOpened
	 *            status of log file opened
	 */
	public void setLogFileOpened(boolean logFileOpened) {
		this.logFileOpened = logFileOpened;

		if (!logFileOpened) {
			openedLogFilePath = null;
		}
	}

	/**
	 * Gets currently opened log file path
	 * 
	 * @return currently opened log file path or null if no log file is open
	 */
	public String getOpenedLogFilePath() {
		return openedLogFilePath;
	}

	/**
	 * Gets currently opened log file name
	 * 
	 * @return currently opened log file name or null if no log file is open
	 */
	public String getOpenedLogFileName() {
		String fileName = null;

		if (openedLogFilePath != null) {
			IPath filePath = new Path(openedLogFilePath);
			fileName = filePath.lastSegment();
		}

		return fileName;
	}
}