package com.commonsensenet.realfarm.utils;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import android.os.Environment;
import android.util.Log;
/**
*
* @author Oscar Bola�os <@oscarbolanos>
*
*/
public class ApplicationTracker {
/** Defines the event types that are trackable through out the application. */
public enum EventType {
ACTIVITY_VIEW, CLICK, ERROR, LONG_CLICK, SYNC
}
/**
* Format used to stored the data in the log. It corresponds to
* <code>[date] userId EventType activityName label </code>
* */
private static final String DATA_ENTRY_FORMAT = "[%s] %d - %s - %s - %s";
/** Shorter format used to store data in the log. */
private static final String DATA_ENTRY_FORMAT_SMALL = "[%s] %d - %s - %s";
/** Format used to store the date information. */
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
/** Default value for the maximum size of the log that will force a flush. */
public static final int DEFAULT_MAX_LOG_SIZE = 5;
/** Name of the file where the log is stored. */
public static final String LOG_FILENAME = "UIlog.txt";
/** Name of the folder where the log is located. */
public static final String LOG_FOLDER = "/.csn_app_logs";
/** Identifier of the class used for logging. */
private static final String LOG_TAG = "ApplicationTracker";
/** Singleton instance of the ActionLogger. */
private static ApplicationTracker sInstance = null;
/**
* Format used to log the Sync events. It is formatted as
* <code>[date] EventType label data</code>
*/
private static final String SYNC_DATA_ENTRY_FORMAT = "[%s] %s - %s - %s";
/** Name of the file where the sync log is stored. */
public static final String SYNC_LOG_FILENAME = "Synclog.txt";
/**
* Gets the singleton instance of the ActionTracker.
*
* @return an ActionTracker instance.
*/
public static ApplicationTracker getInstance() {
if (sInstance == null) {
Log.i(LOG_TAG, "Initializing Application Tracker");
sInstance = new ApplicationTracker();
}
return sInstance;
}
/** Data structure used to store locally the log. */
private LinkedList<String> mActivityLog;
/** Date format used in each log. */
private SimpleDateFormat mDateFormat;
/** DeviceId used to name the log file. */
private String mDeviceId;
/** Path where the log is stored in the SD card. */
private String mExternalDirectoryLog;
/**
* Size of the log that will force the ApplicationTracker to flush its data.
* Set this value to -1 to disable this feature.
*/
public int mMaxLogSize;
/** Data structure used to store the sync events. */
private LinkedList<String> mSyncLog;
private ApplicationTracker() {
// creates the date formatter.
mDateFormat = new SimpleDateFormat(DATE_FORMAT);
// initializes the list where the data will be stored.
mActivityLog = new LinkedList<String>();
mSyncLog = new LinkedList<String>();
// initializes the value with the default
mMaxLogSize = DEFAULT_MAX_LOG_SIZE;
}
/**
* Forces the class to write the activity log
*/
public void flush() {
// cancels the flush operation if there is nothing to flush
synchronized (mActivityLog) {
if (mActivityLog.size() == 0) {
return;
}
}
File mFile;
FileWriter mFileWriter;
File folder = new File(Environment.getExternalStorageDirectory()
+ LOG_FOLDER);
// if the folder does not exist it is created.
if (!folder.exists()) {
folder.mkdir();
}
// gets the path of the folder where the data will be stored.
mExternalDirectoryLog = folder.getAbsolutePath();
// creates the log file.
mFile = new File(mExternalDirectoryLog,
(mDeviceId != null ? (mDeviceId + "-") : "") + LOG_FILENAME);
try {
// initializes the file writer
mFileWriter = new FileWriter(mFile, true);
// forces every line to be a log entry.
PrintWriter pw = new PrintWriter(mFileWriter);
// writes the stored files into the log file.
synchronized (mActivityLog) {
for (int x = 0; x < mActivityLog.size(); x++) {
pw.println(mActivityLog.get(x));
}
// removes all current elements of the list.
mActivityLog.clear();
}
// closes the file writer.
mFileWriter.close();
} catch (Exception e) {
Log.e("WRITE TO SD", e.getMessage());
}
}
public void flushAll() {
// flushes the UI usage data.
flush();
// flushes the sync related data.
flushSync();
}
/**
* Writes the Sync related data into a file in the SD folder.
*/
public void flushSync() {
// cancels the flush operation if there is nothing to flush
synchronized (mSyncLog) {
if (mSyncLog.size() == 0) {
return;
}
}
File mFile;
FileWriter mFileWriter;
File folder = new File(Environment.getExternalStorageDirectory()
+ LOG_FOLDER);
// if the folder does not exist it is created.
if (!folder.exists()) {
folder.mkdir();
}
// gets the path of the folder where the data will be stored.
mExternalDirectoryLog = folder.getAbsolutePath();
// creates the log file.
mFile = new File(mExternalDirectoryLog,
(mDeviceId != null ? (mDeviceId + "-") : "")
+ SYNC_LOG_FILENAME);
try {
// initializes the file writer
mFileWriter = new FileWriter(mFile, true);
// forces every line to be a log entry.
PrintWriter pw = new PrintWriter(mFileWriter);
// writes the stored files into the log file.
synchronized (mSyncLog) {
for (int x = 0; x < mSyncLog.size(); x++) {
pw.println(mSyncLog.get(x));
}
// removes all current elements of the list.
mSyncLog.clear();
}
// closes the file writer.
mFileWriter.close();
} catch (Exception e) {
Log.e("WRITE TO SD", e.getMessage());
}
}
public String getDeviceId() {
return mDeviceId;
}
public int getMaxLogSize() {
return mMaxLogSize;
}
/**
* Logs an event that occurred in the application. Each event has a type,
* the name of the source that generated the event and then optionally any
* other parameter. This can be the name of the button, or any important
* value to record.
*
*
* @param eventType
* type of the event.
* @param userId
* id of the user that performed the activity
* @param activityName
* name of the activity that generated the object.
* @param args
* additional values to log.
*/
public void logEvent(EventType eventType, long userId, String activityName,
Object... args) {
if (args.length == 0) {
switch (eventType) {
case SYNC:
synchronized (mSyncLog) {
mActivityLog.add(String.format(DATA_ENTRY_FORMAT_SMALL,
mDateFormat.format(new Date()), userId, eventType,
activityName));
}
break;
default:
// synchronized access to the log since concurrent access could
// be enabled.
synchronized (mActivityLog) {
mActivityLog.add(String.format(DATA_ENTRY_FORMAT_SMALL,
mDateFormat.format(new Date()), userId, eventType,
activityName));
}
}
} else {
// creates a string with all the available objects.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < args.length; i++) {
// appends the next object.
sb.append(args[i].toString());
// appends a comma and a space.
if (i + 1 < args.length) {
sb.append(", ");
}
}
// synchronized access to the log since concurrent access could be
// enabled.
synchronized (mActivityLog) {
mActivityLog.add(String.format(DATA_ENTRY_FORMAT,
mDateFormat.format(new Date()), userId, eventType,
activityName, sb.toString()));
}
}
// if the maximum size has been exceeded, the data is flushed
// automatically.
synchronized (mActivityLog) {
if (mActivityLog.size() > mMaxLogSize && mMaxLogSize != -1) {
flush();
}
}
}
public void logSyncEvent(EventType eventType, String label, String data) {
synchronized (mSyncLog) {
// creates the entry.
String entry = String.format(SYNC_DATA_ENTRY_FORMAT,
mDateFormat.format(new Date()), eventType, label, data);
// adds the entry to the list.
mSyncLog.add(entry);
// logs the message into log cat.
Log.d(LOG_TAG, entry);
}
// forces the sync data to be written.
flushSync();
// // if the maximum size has been exceeded, the data is flushed
// // automatically.
// synchronized (mSyncLog) {
// if (mSyncLog.size() > mMaxLogSize && mMaxLogSize != -1) {
// flushSync();
// }
// }
}
public void setDeviceId(String deviceId) {
mDeviceId = deviceId;
}
public void setMaxLogSize(int value) {
mMaxLogSize = value;
}
}