Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tm.te.tcf.log.core/src/org/eclipse/tm/te/tcf/log/core/internal/LogManager.java')
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.log.core/src/org/eclipse/tm/te/tcf/log/core/internal/LogManager.java384
1 files changed, 384 insertions, 0 deletions
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.log.core/src/org/eclipse/tm/te/tcf/log/core/internal/LogManager.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.log.core/src/org/eclipse/tm/te/tcf/log/core/internal/LogManager.java
new file mode 100644
index 000000000..23c435b98
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.log.core/src/org/eclipse/tm/te/tcf/log/core/internal/LogManager.java
@@ -0,0 +1,384 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. 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:
+ * Uwe Stieber (Wind River) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.log.core.internal;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.te.tcf.core.Tcf;
+import org.eclipse.tm.te.tcf.core.interfaces.listeners.IChannelStateChangeListener;
+import org.eclipse.tm.te.tcf.core.interfaces.listeners.IProtocolStateChangeListener;
+import org.eclipse.tm.te.tcf.log.core.activator.CoreBundleActivator;
+import org.eclipse.tm.te.tcf.log.core.interfaces.IPreferenceKeys;
+import org.eclipse.tm.te.tcf.log.core.internal.listener.ChannelStateChangeListener;
+import org.eclipse.tm.te.tcf.log.core.internal.listener.ChannelTraceListener;
+import org.eclipse.tm.te.tcf.log.core.internal.nls.Messages;
+
+
+/**
+ * Target Explorer: TCF logging log manager implementation.
+ */
+public final class LogManager implements IProtocolStateChangeListener {
+ // Reference to the channel state change listener
+ private IChannelStateChangeListener channelStateChangeListener;
+
+ // Maps file writer per log file base name
+ private final Map<String, FileWriter> fileWriterMap = new HashMap<String, FileWriter>();
+
+ // Maximum log file size in bytes
+ private long maxFileSize;
+ // Maximum number of files in cycle
+ private int maxInCycle;
+
+ /*
+ * Thread save singleton instance creation.
+ */
+ private static class LazyInstance {
+ public static LogManager instance = new LogManager();
+ }
+
+ /**
+ * Constructor.
+ */
+ /* default */ LogManager() {
+ super();
+
+ // initialize from preferences
+ initializeFromPreferences();
+ }
+
+ /**
+ * Returns the singleton instance.
+ */
+ public static LogManager getInstance() {
+ return LazyInstance.instance;
+ }
+
+ /**
+ * Dispose the log manager instance.
+ */
+ public void dispose() {
+ String message = NLS.bind(Messages.ChannelTraceListener_logManagerDispose_message,
+ ChannelTraceListener.DATE_FORMAT.format(new Date(System.currentTimeMillis())));
+ for (FileWriter writer : fileWriterMap.values()) {
+ try {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ } catch (IOException e) {
+ /* ignored on purpose */
+ } finally {
+ try {
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+ fileWriterMap.clear();
+ }
+
+ /**
+ * Initialize the log manager based on the current
+ * preference settings
+ */
+ private void initializeFromPreferences() {
+ String fileSize = Platform.getPreferencesService().getString(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_MAX_FILE_SIZE, "5M", null); //$NON-NLS-1$
+
+ try {
+ // If the last character is either K, M or G -> convert to bytes
+ char lastChar = fileSize.toUpperCase().charAt(fileSize.length() - 1);
+ if ('K' == lastChar || 'M' == lastChar || 'G' == lastChar) {
+ maxFileSize = Long.parseLong(fileSize.substring(0, fileSize.length() - 1));
+ switch (lastChar) {
+ case 'K':
+ maxFileSize = maxFileSize * 1024;
+ break;
+ case 'M':
+ maxFileSize = maxFileSize * 1024 * 1024;
+ break;
+ case 'G':
+ maxFileSize = maxFileSize * 1024 * 1024 * 1024;
+ break;
+ }
+ } else {
+ maxFileSize = Long.parseLong(fileSize);
+ }
+ } catch (NumberFormatException e) {
+ maxFileSize = 5242880L;
+ }
+
+ maxInCycle = Platform.getPreferencesService().getInt(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_MAX_FILES_IN_CYCLE, 5, null);
+ }
+
+ /**
+ * Create, register and initialize the listeners.
+ * <p>
+ * <b>Note:</b> This method is supposed to be called from {@link Startup} only!
+ */
+ /* default */ final void initListeners() {
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // If the channel state change listener instance has been created
+ // already, there is nothing left to do here
+ if (channelStateChangeListener != null) return;
+
+ // Register ourself as protocol change listener
+ Tcf.addProtocolStateChangeListener(this);
+
+ // Create and register the channel state change listener
+ channelStateChangeListener = new ChannelStateChangeListener();
+ Tcf.addChannelStateChangeListener(channelStateChangeListener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.core.interfaces.listeners.IProtocolStateChangeListener#stateChanged(boolean)
+ */
+ public void stateChanged(boolean state) {
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // On shutdown, get the listener removed and disposed
+ if (!state) {
+ Tcf.removeChannelStateChangeListener(channelStateChangeListener);
+ channelStateChangeListener = null;
+
+ Tcf.removeProtocolStateChangeListener(this);
+ }
+ }
+
+ /**
+ * Returns the file writer instance to use for the given channel.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The file writer instance or <code>null</code>.
+ */
+ public FileWriter getWriter(IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // Before looking up the writer, check the file limits
+ checkLimits(channel);
+
+ String logName = getLogName(channel);
+ FileWriter writer = logName != null ? fileWriterMap.get(logName) : null;
+ if (writer == null && logName != null) {
+ // Create the writer
+ IPath path = getLogDir();
+ if (path != null) {
+ path = path.append(logName + ".log"); //$NON-NLS-1$
+ try {
+ writer = new FileWriter(path.toFile(), true);
+ fileWriterMap.put(logName, writer);
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+
+ return writer;
+ }
+
+ /**
+ * Close the writer instance used for the given channel.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @param message The last message to write or <code>null</code>.
+ */
+ public void closeWriter(IChannel channel, String message) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // Remove the writer from the map
+ String logName = getLogName(channel);
+ FileWriter writer = logName != null ? fileWriterMap.remove(logName) : null;
+ if (writer != null) {
+ try {
+ // If specified, write the last message.
+ if (message != null) {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ }
+ } catch (IOException e) {
+ /* ignored on purpose */
+ } finally {
+ try {
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the log file base name for the given peer id.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The log file base name.
+ */
+ protected String getLogName(IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ String logName = null;
+
+ IPeer peer = channel.getRemotePeer();
+ if (peer != null) {
+ // Get the peer name
+ logName = peer.getName();
+
+ // Get the peer host IP address
+ String ip = peer.getAttributes().get(IPeer.ATTR_IP_HOST);
+ // Fallback: The peer id
+ if (ip == null || "".equals(ip.trim())) { //$NON-NLS-1$
+ ip = peer.getID();
+ }
+
+ // Append the peer host IP address
+ if (ip != null && !"".equals(ip.trim())) { //$NON-NLS-1$
+ logName += " " + ip.trim(); //$NON-NLS-1$
+ }
+
+ // Unify name and replace all undesired characters with '_'
+ logName = makeValid(logName);
+ }
+
+ return logName;
+ }
+
+ /**
+ * Replaces a set of predefined patterns with underscore to
+ * make a valid name.
+ *
+ * @param name The name. Must not be <code>null</code>.
+ * @return The modified name.
+ */
+ private String makeValid(String name) {
+ Assert.isNotNull(name);
+
+ String result = name.replaceAll("\\s", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+ result = result.replaceAll("[:/\\;,]", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ return result;
+ }
+
+ /**
+ * Returns the log directory.
+ *
+ * @return The log directory.
+ */
+ private IPath getLogDir() {
+ IPath logDir = null;
+
+ try {
+ File file = CoreBundleActivator.getDefault().getStateLocation().append(".logs").toFile(); //$NON-NLS-1$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ } catch (IllegalStateException e) {
+ // Ignored: Workspace less environment (-data @none)
+ }
+
+ if (logDir == null) {
+ // First fallback: ${HOME}/.tcf/.logs
+ File file = new Path(System.getProperty("user.home")).append(".tcf/.logs").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ }
+
+ if (logDir == null) {
+ // Second fallback: ${TEMP}/.tcf/.logs
+ File file = new Path(System.getProperty("java.io.tmpdir")).append(".tcf/.logs").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ }
+
+ return logDir;
+ }
+
+ /**
+ * Checks the limits set by the preferences.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The checked file writer instance.
+ */
+ private void checkLimits(IChannel channel) {
+ Assert.isNotNull(channel);
+
+ String logName = getLogName(channel);
+ if (logName != null && !"".equals(logName.trim())) { //$NON-NLS-1$
+ IPath path = getLogDir();
+ if (path != null) {
+ IPath fullPath = path.append(logName + ".log"); //$NON-NLS-1$
+ File file = fullPath.toFile();
+ if (file.exists()) {
+ long size = file.length();
+ if (size >= maxFileSize) {
+ // Max log file size reached -> cycle files
+
+ // If there is an active writer, flush and close the writer
+ closeWriter(channel, null);
+
+ // Determine if the maximum number of files in the cycle has been reached
+ File maxFileInCycle = path.append(logName + "_" + maxInCycle + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (maxFileInCycle.exists()) {
+ // We have to rotate the full cycle, first in cycle to be removed.
+ int no = 1;
+ File fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ fileInCycle.delete();
+
+ while (no <= maxInCycle) {
+ no++;
+ fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ File renameTo = path.append(logName + "_" + (no - 1) + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ fileInCycle.renameTo(renameTo);
+ }
+
+ // Rename the log file
+ file.renameTo(maxFileInCycle);
+ } else {
+ // Not at the limit, find the next file name in the cycle
+ int no = 1;
+ File fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ while (fileInCycle.exists()) {
+ no++;
+ fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ Assert.isTrue(no <= maxInCycle);
+
+ // Rename the log file
+ file.renameTo(fileInCycle);
+ }
+ }
+ }
+ }
+ }
+ }
+}

Back to the top