package uk.org.smithfamily.mslogger.log;
import java.io.*;
import uk.org.smithfamily.mslogger.ApplicationSettings;
import android.os.Environment;
import android.util.Log;
/**
* Class that is used to help debugging. Will log the specified log level to a log file that can be sent by users to developers
*/
public enum DebugLogManager
{
INSTANCE;
private final static boolean ALWAYS_LOG_TO_FILE = false;
private File logFile;
private FileWriter os;
private String absolutePath;
private final int MAX_LOG_FILE_SIZE_THRESHOLD = 5120; // (1024 * 5)B = 5120KB = 5MB
/**
* Create the log file where the log will be saved
*
* @throws IOException
*/
private void createLogFile() throws IOException
{
if (!ApplicationSettings.INSTANCE.isWritable())
{
return;
}
final File dir = new File(Environment.getExternalStorageDirectory(), "MSLogger");
dir.mkdirs();
boolean append = true;
if (logFile == null)
{
final String fileName = "debugLog.txt";
logFile = new File(dir, fileName);
}
// If log file have reached threshold, don't append to it, overwrite it instead
if (logFile.length() >= MAX_LOG_FILE_SIZE_THRESHOLD)
{
append = false;
}
absolutePath = logFile.getAbsolutePath();
os = new FileWriter(logFile, append);
}
/**
* Main function to write in the log file
*
* @param s The log to write
* @param logLevel The level of log
*/
public void log(final String s, final int logLevel)
{
// Make sure the user want to save a log of that level
if (!checkLogLevel(logLevel))
{
return;
}
// Make sure we have write permission
if (!ApplicationSettings.INSTANCE.isWritable())
{
return;
}
Log.println(logLevel, "MSLogger", s);
if (ALWAYS_LOG_TO_FILE || (logLevel <= Log.DEBUG))
{
try
{
if ((logFile == null) || (os == null))
{
createLogFile();
}
final long now = System.currentTimeMillis();
synchronized (os)
{
os.write(String.format("%tc:%tL:%s:%s%n", now, now, Thread.currentThread().getName(), s));
os.flush();
}
}
catch (final IOException e)
{
System.err.println("Could not write '" + s + "' to the log file : " + e.getLocalizedMessage());
}
}
}
/**
* Check if the user preference is set to accept the specified log level
*
* @param logLevel The specified log level of the user
* @return true if log is accepted, false otherwise
*/
public static boolean checkLogLevel(final int logLevel)
{
return (ALWAYS_LOG_TO_FILE || (ApplicationSettings.INSTANCE.getLoggingLevel() <= logLevel));
}
/**
* Log exception into the log file
*
* @param ex The exception to log
*/
public void logException(final Exception ex)
{
// Make sure we have write permission
if (!ApplicationSettings.INSTANCE.isWritable())
{
return;
}
if (os == null)
{
try
{
createLogFile();
}
catch (final IOException e)
{
System.err.println("Could not create the log file : " + e.getLocalizedMessage());
}
}
synchronized (os)
{
final PrintWriter pw = new PrintWriter(os);
try
{
final long now = System.currentTimeMillis();
os.write(String.format("%tc:%tL:%s:%s%n", now, now, Thread.currentThread().getName(), ex.getLocalizedMessage()));
}
catch (final IOException e)
{
}
ex.printStackTrace(pw);
try
{
if (os != null)
{
os.flush();
}
}
catch (final IOException e)
{
}
}
}
/**
* @return The absolute path to the log file
*/
public String getAbsolutePath()
{
return absolutePath;
}
/**
* This helper function can be used to log a bytes array to log, prefixed by the specified message
*
* @param msg Log to be saved
* @param result Bytes to be saved after the log
* @param logLevel The log level
*/
public void log(final String msg, final byte[] result, final int logLevel)
{
if (!checkLogLevel(logLevel))
{
return;
}
final StringBuffer b = new StringBuffer(msg).append("\n");
StringBuffer text = new StringBuffer();
StringBuffer hex = new StringBuffer();
for (int i = 0; i < result.length; i++)
{
final char c = (char) result[i];
hex.append(String.format(" %02x", result[i]));
if ((c >= 32) && (c <= 127))
{
text.append(c);
}
else
{
text.append('.');
}
if (((i + 1) % 40) == 0)
{
b.append(hex).append(" ").append(text).append("\n");
text = new StringBuffer();
hex = new StringBuffer();
}
}
if (text.length() > 0)
{
b.append(String.format("%1$-120s %2$s\n", hex.toString(), text.toString()));
}
log(b.toString(), logLevel);
}
}