/*******************************************************************************
* Copyright (c) 2006 IBM Corporation 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:
* IBM Corporation - Jeff Briggs, Henry Hughes, Ryan Morse
* Red Hat - ongoing maintenance
*******************************************************************************/
package org.eclipse.linuxtools.systemtap.structures;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.linuxtools.internal.systemtap.structures.Localization;
import org.eclipse.linuxtools.systemtap.structures.listeners.IGobblerListener;
/**
* A utility for saving script output to a log file as it runs.
*/
public class LoggingStreamDaemon implements IGobblerListener {
private static final int BUFFER_SIZE = 1024;
private static final Set<LoggingStreamDaemon> allLogs = new HashSet<>();
protected StringBuilder output;
protected File outputFile;
protected FileWriter writer;
private boolean saveLog = false;
/**
* Sets up a new logger. Log contents will be saved to a temporary file
* until {@link #saveLog} is used to save the log to a specified file.
*/
public LoggingStreamDaemon() {
output = new StringBuilder();
try {
outputFile = File.createTempFile(this.toString(), ".tmp"); //$NON-NLS-1$
writer = new FileWriter(outputFile, true);
} catch (IOException ioe) {
outputFile = null;
writer = null;
}
}
/**
* Pushes output to log.
*/
private void pushData() {
try {
// Recreate the log if it was deleted
if (!outputFile.exists()) {
startRestoredLog();
}
writer.write(output.toString());
output.setLength(0);
writer.flush();
} catch (IOException ioe) {}
}
/**
* Outputs one line.
*/
@Override
public void handleDataEvent(String line) {
if (isReady()) {
output.append(line);
pushData();
}
}
/**
* Reads in and returns the output produced.
* @return The logged data.
*/
public String getOutput() {
if (!isReady()) {
return null;
}
if (output.length() > 0) {
pushData();
}
try (FileReader reader = new FileReader(outputFile)) {
char[] buffer = new char[BUFFER_SIZE];
int count;
StringBuilder builder = new StringBuilder();
while (-1 != (count = reader.read(buffer))) {
builder.append(buffer, 0, count);
}
return builder.toString();
} catch (IOException ioe) {
return null;
}
}
/**
* Sets the logging stream to be continuously saved to a file.
* @param file The file to save the log data to. Must not be <code>null</code>.
* @return <code>true</code> if the save was successful, <code>false</code> otherwise.
*/
public boolean saveLog(File file) {
if (!isReady()) {
return false;
}
// If saving to the same file that's already being saved to,
// either do nothing if it exists, or restore it if it doesn't.
if (file.equals(outputFile)) {
if (!outputFile.exists()) {
try {
startRestoredLog();
} catch (IOException e) {
return false;
}
}
return true;
}
// If saving to a file used by another active log,
// quit to avoid write conflicts.
for (LoggingStreamDaemon log : allLogs) {
if (!log.equals(this) && file.equals(log.outputFile)) {
return false;
}
}
try {
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
FileWriter w = new FileWriter(file, false);
try (FileReader r = new FileReader(outputFile)) {
char[] buffer = new char[BUFFER_SIZE];
int count;
while (-1 != (count = r.read(buffer))) {
w.write(new String(buffer, 0, count));
}
}
w.flush();
writer.close();
writer = w;
} catch (IOException ioe) {
return false;
}
outputFile.delete();
outputFile = file;
saveLog = true;
allLogs.add(this);
return true;
}
private void startRestoredLog() throws IOException {
outputFile.createNewFile();
output.insert(0, Localization.getString("LoggingStreamDaemon.ResumedLog") + '\n'); //$NON-NLS-1$
writer.close();
writer = new FileWriter(outputFile, false);
}
public void dispose() {
if (outputFile != null) {
if (!saveLog) {
outputFile.delete();
}
outputFile = null;
}
if (writer != null) {
try {
writer.close();
} catch(IOException ioe) {}
writer = null;
}
if (output != null) {
output.setLength(0);
output = null;
}
allLogs.remove(this);
}
private boolean isReady() {
return writer != null && outputFile != null;
}
}