aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Kropf <josh@slashdev.ca>2011-05-25 16:24:18 (GMT)
committerJosh Kropf <josh@slashdev.ca>2011-05-25 16:24:18 (GMT)
commitd1aeb00ce4e5684130306bdf74a90d66734d5d57 (patch)
tree635e18265eb4b7bbdde747ec908dac3f8cb56a67
downloadlog4bb-d1aeb00ce4e5684130306bdf74a90d66734d5d57.zip
log4bb-d1aeb00ce4e5684130306bdf74a90d66734d5d57.tar.gz
log4bb-d1aeb00ce4e5684130306bdf74a90d66734d5d57.tar.bz2
initial commit
-rw-r--r--LICENSE4
-rw-r--r--README15
-rw-r--r--build.properties9
-rw-r--r--build.xml62
-rw-r--r--project.properties6
-rw-r--r--src/com/jiggak/log/LogAdapter.java48
-rw-r--r--src/com/jiggak/log/Logger.java249
-rw-r--r--src/com/jiggak/log/adapter/BluetoothAdapter.java168
-rw-r--r--src/com/jiggak/log/adapter/EventLoggerAdapter.java57
-rw-r--r--src/com/jiggak/log/adapter/RollingAdapter.java88
-rw-r--r--src/com/jiggak/log/adapter/StdoutAdapter.java26
11 files changed, 732 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e6ffa49
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,4 @@
+"THE BEER-WARE LICENSE" (Revision 42):
+<josh@slashdev.ca> wrote this file. As long as you retain this notice you
+can do whatever you want with this stuff. If we meet some day, and you think
+this stuff is worth it, you can buy me a beer in return Josh Kropf \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..add1593
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+log4bb is a simple logging framework for BlackBerry that resembles the
+popular log4j framework in syntax. However log4bb abstracts the logging
+interface API used by your program from the destination of the log output.
+
+Four logging adapters are provided: standard output, eventlog, rolling, and
+bluetooth serial. Adapters can be registered or unregistered at runtime.
+
+StdoutAdapter prints to standard out. Useful only when a debugger is attached
+to the simulator or device.
+
+EventLoggerAdapter prints to the device event log.
+
+RollingAdapter keeps log contents in memory using a circular buffer.
+
+BluetoothAdapter sends log output across a standard bluetooth serial port. \ No newline at end of file
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..b858b26
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,9 @@
+# the current jde used for compile, sign, javaloader
+jde.home = /home/josh/local/lib/JDE5.0.0
+
+# simulator home, where cod files are copied to
+simulator.home = ${jde.home}/simulator
+
+# signature tool properties, to use auto-signing 4.3 jde is required
+sigtool.jde = ${jde.home}
+sigtool.password = password \ No newline at end of file
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..ecb495f
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="log4bb" default="build">
+ <taskdef resource="bb-ant-defs.xml" />
+
+ <!-- import project properties (project basedir is searched) -->
+ <property prefix="project" file="project.properties" />
+
+ <property file="build.properties" />
+ <property name="build.dir" location="build" />
+
+ <path id="src.files">
+ <fileset dir="src" includes="**/*" />
+ </path>
+
+ <target name="build">
+ <mkdir dir="${build.dir}" />
+ <rapc quiet="true" output="${project.output}" destdir="${build.dir}">
+ <src refid="src.files" />
+ <jdp file="${basedir}/project.properties" />
+ </rapc>
+ </target>
+
+ <target name="clean">
+ <delete dir="build" />
+ </target>
+
+ <target name="sign" depends="build">
+ <sigtool jdehome="${sigtool.jde}" password="${sigtool.password}">
+ <fileset dir="build" includes="*.cod" />
+ </sigtool>
+ <!-- delete that damn pesky log file -->
+ <delete file="LogFile.txt" />
+ </target>
+
+ <target name="load-device" depends="sign">
+ <exec executable="${jde.home}/bin/JavaLoader.exe">
+ <arg value="-usb" />
+ <arg value="load" />
+ <arg file="build/*.cod" />
+ </exec>
+ </target>
+
+ <target name="load-simulator" depends="build">
+ <antcall target="export-all">
+ <param name="export.dir" value="${simulator.home}" />
+ </antcall>
+ </target>
+
+ <target name="export" if="export.dir" depends="build">
+ <mkdir dir="${export.dir}" />
+ <copy todir="${export.dir}">
+ <fileset dir="build" includes="*.cod" />
+ </copy>
+ </target>
+
+ <target name="export-all" if="export.dir" depends="build">
+ <mkdir dir="${export.dir}" />
+ <copy todir="${export.dir}">
+ <fileset dir="build" includes="*.cod,*.csl,*.cso,*.debug,*.jar" />
+ </copy>
+ </target>
+</project> \ No newline at end of file
diff --git a/project.properties b/project.properties
new file mode 100644
index 0000000..2e9f424
--- /dev/null
+++ b/project.properties
@@ -0,0 +1,6 @@
+output = com_jiggak_log4bb
+type = library
+title = log4bb
+vendor = Josh Kropf
+version = 1.0
+desc = Extensible logging classes \ No newline at end of file
diff --git a/src/com/jiggak/log/LogAdapter.java b/src/com/jiggak/log/LogAdapter.java
new file mode 100644
index 0000000..26be7ba
--- /dev/null
+++ b/src/com/jiggak/log/LogAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log;
+
+/**
+ * Interface for logging subsystems.
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public abstract class LogAdapter {
+ /**
+ * Initializes the logging system
+ * @param init optional intialization parameter
+ */
+ public abstract void create(Object init);
+
+ /**
+ * Handles unregistering of the logging system
+ */
+ public abstract void destroy();
+
+ /**
+ * Logs a message to the logging system.
+ * @param message
+ * @param level one of the constants defined in Logger.LEVEL_*
+ */
+ public abstract void log(String message, int level);
+
+ /**
+ * The {@link Logger} class will use the {@link Object#equals(Object)}
+ * method and pass it the adapter class name (without the package) to test
+ * for equality.
+ */
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+
+ if (obj instanceof String) {
+ return this.getClass().getName().indexOf(obj.toString()) != -1;
+ }
+
+ return super.equals(obj);
+ }
+}
diff --git a/src/com/jiggak/log/Logger.java b/src/com/jiggak/log/Logger.java
new file mode 100644
index 0000000..ec4b7b0
--- /dev/null
+++ b/src/com/jiggak/log/Logger.java
@@ -0,0 +1,249 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log;
+
+import java.util.Vector;
+
+import net.rim.device.api.system.RuntimeStore;
+import net.rim.device.api.util.StringUtilities;
+
+/**
+ * Central logging class. By default, the event logger is always registered.
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public final class Logger {
+
+ public static final int LEVEL_ERROR = 1;
+ public static final int LEVEL_WARN = 2;
+ public static final int LEVEL_INFO = 4;
+ public static final int LEVEL_DEBUG = 8;
+
+ private static final String ADAPTER_PACKAGE = "com.jiggak.log.adapter";
+ private static final String HASH = "com.jiggak.log.logger";
+ private static final long ID = StringUtilities.stringHashToLong(HASH);
+ private static RuntimeStore runtime = RuntimeStore.getRuntimeStore();
+
+ static {
+ // register the event log adapter by default
+ register("EventLoggerAdapter");
+ }
+
+ // string prefix for log messages
+ private String prefix;
+
+ /*
+ * Creates Log class with the given string prefix for all log messages
+ */
+ private Logger(String prefix) {
+ this.prefix = prefix;
+ }
+
+ private static Vector adapters() {
+ Vector adapters = (Vector)runtime.get(ID);
+ if (adapters == null) runtime.put(ID, adapters=new Vector());
+ return adapters;
+ }
+
+ /**
+ * Gets an instance of Logger that logs messages for the given class
+ * @param clazz
+ * @return logger instance
+ */
+ public static Logger getLogger(Class clazz) {
+ // Class.getName returns fully qualified class name
+ String fqn = clazz.getName();
+
+ // get just the class name
+ String name = fqn.substring(fqn.lastIndexOf('.')+1);
+ return new Logger("["+name+"] ");
+ }
+
+ /**
+ * Registers a new log adapter
+ * @param adapterName class name (without package) of log adapter to register
+ * @param init optional initialization parameter
+ */
+ public static void register(String adapterName, Object init) {
+ Vector adapters = adapters();
+ if (adapters.contains(new Finder(adapterName))) {
+ unregister(adapterName);
+ }
+
+ LogAdapter adapter = null;
+
+ try {
+ String className = ADAPTER_PACKAGE + "." + adapterName;
+ adapter = (LogAdapter)Class.forName(className).newInstance();
+ adapter.create(null);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(adapterName+" class not found");
+ } catch (Exception e) {
+ throw new RuntimeException(adapterName+" instantiation failed: "+e);
+ }
+
+ adapters.addElement(adapter);
+ }
+
+ /**
+ * Regsiter a new log adapter. Passes null for initialization parameter
+ * @see Logger#register(String, Object)
+ */
+ public static void register(String adapterName) {
+ register(adapterName, null);
+ }
+
+ /**
+ * Unregisters a log adapter
+ * @param adapterName class name (without package)
+ * @return true if adapter was found and unregistered
+ */
+ public static boolean unregister(String adapterName) {
+ Vector adapters = adapters();
+
+ int i = adapters.indexOf(new Finder(adapterName));
+ if (i != -1) {
+ LogAdapter a = (LogAdapter)adapters.elementAt(i);
+ a.destroy();
+
+ adapters.removeElementAt(i);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get instance of registered adapter
+ * @param adapterName name of registered adapter
+ * @return instance of adapter, or null if the adapter is not yet registered
+ */
+ public static LogAdapter getAdapter(String adapterName) {
+ Vector adapters = adapters();
+ for (int i=0, size=adapters.size(); i<size; i++) {
+ if (adapters.elementAt(i).getClass().getName().endsWith(adapterName))
+ return (LogAdapter)adapters.elementAt(i);
+ }
+
+ return null;
+ }
+
+ /**
+ * Lists currently registered adapters
+ * @return registered adapter names
+ */
+ public static String[] listRegistered() {
+ Vector adapters = adapters();
+ String[] retval = new String[adapters.size()];
+ String name;
+
+ for (int i=adapters.size()-1; i>=0; i--) {
+ name = adapters.elementAt(i).getClass().getName();
+ retval[i] = name.substring(name.lastIndexOf('.')+1);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Lists all available adapters
+ * @return available adapter names
+ */
+ public static String[] listAvailable() {
+ //TODO make adapter list dynamic
+ return new String[] {"BluetoothAdapter", "EventLoggerAdapter",
+ "StdoutAdapter", "RollingAdapter"};
+ }
+
+ /*
+ * Central logging method... logs message to each logging system
+ */
+ private void log(String msg, int level) {
+ LogAdapter a;
+ Vector adapters = adapters();
+ for (int i=adapters.size()-1; i>=0; i--) {
+ a = (LogAdapter)adapters.elementAt(i);
+ a.log(prefix+msg, level);
+ }
+ }
+
+ /**
+ * Returns string representation of the log level
+ * @param level log leve
+ * @return string representation
+ */
+ public static String levelToString(int level) {
+ switch (level) {
+ case LEVEL_ERROR: return "ERROR";
+ case LEVEL_WARN: return "WARN";
+ case LEVEL_INFO: return "INFO";
+ case LEVEL_DEBUG: return "DEBUG";
+ default: return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Logs a debug message
+ * @param msg log message
+ */
+ public void debug(String msg) {
+ log(msg, LEVEL_DEBUG);
+ }
+
+ /**
+ * Logs an information message
+ * @param msg log message
+ */
+ public void info(String msg) {
+ log(msg, LEVEL_INFO);
+ }
+
+ /**
+ * Logs a warning message
+ * @param msg log message
+ */
+ public void warn(String msg) {
+ log(msg, LEVEL_WARN);
+ }
+
+ /**
+ * Logs an error message
+ * @param msg log message
+ */
+ public void error(String msg) {
+ log(msg, LEVEL_ERROR);
+ }
+
+ /**
+ * Logs an error message and appends the class name of the exception
+ * and the exception message
+ * @param msg log message
+ * @param t exception
+ */
+ public void error(String msg, Throwable t) {
+ String str = msg+", cause: "+t.getClass()+", message: "+t.getMessage();
+ log(str, LEVEL_ERROR);
+ }
+}
+
+class Finder {
+ private String _adapterName;
+
+ public Finder(String adapterName) {
+ _adapterName = adapterName;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof LogAdapter) {
+ return obj.equals(_adapterName);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/com/jiggak/log/adapter/BluetoothAdapter.java b/src/com/jiggak/log/adapter/BluetoothAdapter.java
new file mode 100644
index 0000000..ae2e753
--- /dev/null
+++ b/src/com/jiggak/log/adapter/BluetoothAdapter.java
@@ -0,0 +1,168 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log.adapter;
+
+import java.io.IOException;
+
+import net.rim.device.api.bluetooth.BluetoothSerialPort;
+import net.rim.device.api.bluetooth.BluetoothSerialPortListener;
+import net.rim.device.api.util.DataBuffer;
+
+import com.jiggak.log.LogAdapter;
+import com.jiggak.log.Logger;
+
+/**
+ * <p>Bluetooth logger class is a revolutionary invention. It slices, it dices,
+ * and it writes logging messages across a bluetooth serial port in real time!
+ * You hear that? REAL TIME!!!
+ *
+ * <p>The serial port connection is initiated by the client side. For best
+ * results on windows, have your application create the BluetoothLogger instance
+ * before you attempt to pair the blackberry to the pc. This will insure
+ * that Winblows finds the serial port and gives it a com port number.
+ *
+ * <p>Use any old terminal emulation software (HyperTerminal, Putty) and set
+ * the paramters to:
+ *
+ * <ul>
+ * <li>Baud: 115200</li>
+ * <li>Data Bits: 8</li>
+ * <li>Stop Bits: 1</li>
+ * <li>Parity: None</li>
+ * <li>Flow Control: None</li>
+ * </ul>
+ *
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public final class BluetoothAdapter extends LogAdapter
+ implements BluetoothSerialPortListener, Runnable
+{
+ public static final String SERVICE_NAME = "BluetoothLogAdapter";
+
+ private BluetoothSerialPort _port;
+
+ private boolean _connected, _ready = true;
+
+ private DataBuffer _buffer = new DataBuffer();
+
+ /**
+ * If the device supports bluetooth, bluetooth serial port is initialized
+ * @param init bluetooth service name when non-null
+ */
+ public void create(Object init) {
+ if (BluetoothSerialPort.isSupported()) {
+ String serviceName = init != null? init.toString() : SERVICE_NAME;
+
+ try {
+ _port = new BluetoothSerialPort(serviceName,
+ BluetoothSerialPort.BAUD_115200,
+ BluetoothSerialPort.DATA_FORMAT_PARITY_NONE |
+ BluetoothSerialPort.DATA_FORMAT_STOP_BITS_1 |
+ BluetoothSerialPort.DATA_FORMAT_DATA_BITS_8,
+ BluetoothSerialPort.FLOW_CONTROL_NONE,
+ 1024, 1024, // receive, send buffer sizes
+ this);
+ } catch (IOException e) {
+ throw new RuntimeException("io exception creating bluetooth logger");
+ }
+ }
+ }
+
+ public void destroy() {
+ if (_port != null) {
+ _port.close();
+ }
+ }
+
+ public void log(String msg, int level) {
+ if (_connected) {
+ StringBuffer buff = new StringBuffer();
+ buff.append(Logger.levelToString(level)).append(' ');
+ buff.append(msg).append('\n').append('\r');
+
+ synchronized (_buffer) {
+ _buffer.write(buff.toString().getBytes());
+ synchronized (this) { notify(); }
+ }
+ }
+ }
+
+ public void run() {
+ while (_connected) {
+ try {
+ synchronized (this) { wait(); }
+ } catch (InterruptedException e) {
+ //TODO warn that transmit thread just died
+ _connected = false;
+ return;
+ }
+
+ if (_buffer.getArrayLength() > 0 && _ready) {
+ try {
+ _ready = false;
+
+ synchronized (_buffer) {
+ _port.write(_buffer.getArray(), 0, _buffer.getArrayLength());
+ _buffer.reset();
+ }
+ } catch (IOException e) {
+ //TODO warn io error in bluetooth log adapter
+ _ready = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * @see BluetoothSerialPortListener#dataReceived(int)
+ */
+ public void dataReceived(int length) { }
+
+ /**
+ * @see BluetoothSerialPortListener#dataSent()
+ */
+ public void dataSent() {
+ _ready = true;
+
+ // notify transmit thread to send data (if there is any)
+ synchronized (this) { notify(); }
+ }
+
+ /**
+ * @see BluetoothSerialPortListener#deviceConnected(boolean)
+ */
+ public void deviceConnected(boolean success) {
+ if (success) {
+ _connected = true;
+
+ // start transmit thread when uppon device connection
+ // it will automatically return when device disconnects
+ new Thread(this).start();
+
+ // wait for the transmit thread to get started before salutation
+ try { Thread.sleep(2000); }
+ catch (InterruptedException e) { }
+
+ // great the new connection
+ log("Don't Panic", Logger.LEVEL_INFO);
+ } else {
+ //TODO warn bluetooth spp connection failed
+ }
+ }
+
+ /**
+ * @see BluetoothSerialPortListener#deviceDisconnected()
+ */
+ public void deviceDisconnected() { _connected = false; }
+
+ /**
+ * @see BluetoothSerialPortListener#dtrStateChange(boolean)
+ */
+ public void dtrStateChange(boolean high) { }
+}
diff --git a/src/com/jiggak/log/adapter/EventLoggerAdapter.java b/src/com/jiggak/log/adapter/EventLoggerAdapter.java
new file mode 100644
index 0000000..e922da6
--- /dev/null
+++ b/src/com/jiggak/log/adapter/EventLoggerAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log.adapter;
+
+import net.rim.device.api.system.EventLogger;
+import net.rim.device.api.util.StringUtilities;
+
+import com.jiggak.log.LogAdapter;
+import com.jiggak.log.Logger;
+
+/**
+ * Sends log messages to the blackberry EventLogger system.
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public final class EventLoggerAdapter extends LogAdapter {
+ private static final String HASH = "com.jiggak.log.EventLogAdapter";
+ private static final long GUID = StringUtilities.stringHashToLong(HASH);
+
+ // this name is used by event viewer for filtering
+ private static final String DEFAULT_NAME = "log4bb";
+
+ public void create(Object init) {
+ String name = init != null? init.toString() : DEFAULT_NAME;
+ EventLogger.register(GUID, name, EventLogger.VIEWER_STRING);
+ }
+
+ public void destroy() {
+ // can't unregister with event logger for some crazzy reason
+ }
+
+ public void log(String message, int level) {
+ EventLogger.logEvent(GUID, message.getBytes(), convert(level));
+ }
+
+ /*static void alwaysLog(String message) {
+ EventLogger.logEvent(GUID, message.getBytes());
+ }*/
+
+ /*
+ * converts between libLogger log levels to blackberry event logger levels
+ */
+ private static int convert(int level) {
+ switch (level) {
+ case Logger.LEVEL_ERROR: return EventLogger.ERROR;
+ case Logger.LEVEL_WARN: return EventLogger.WARNING;
+ case Logger.LEVEL_INFO: return EventLogger.INFORMATION;
+ case Logger.LEVEL_DEBUG: return EventLogger.DEBUG_INFO;
+ default: return EventLogger.ALWAYS_LOG;
+ }
+ }
+}
diff --git a/src/com/jiggak/log/adapter/RollingAdapter.java b/src/com/jiggak/log/adapter/RollingAdapter.java
new file mode 100644
index 0000000..b2631eb
--- /dev/null
+++ b/src/com/jiggak/log/adapter/RollingAdapter.java
@@ -0,0 +1,88 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log.adapter;
+
+import java.util.Date;
+
+import net.rim.device.api.i18n.SimpleDateFormat;
+
+import com.jiggak.log.LogAdapter;
+import com.jiggak.log.Logger;
+
+/**
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public class RollingAdapter extends LogAdapter {
+
+ private static SimpleDateFormat FMT = new SimpleDateFormat("MMM dd HH:mm:ss:SSS");
+
+ // default maximum number of entries in messages array
+ private static final int DEFAULT_MAX = 100;
+
+ private String[] _messages;
+
+ // current index for inserting into messages array
+ private int _index = -1;
+
+ /**
+ * Creates a new rolling log adapter with an empty array of messages
+ * @see LogAdapter#create(java.lang.Object)
+ */
+ public void create(Object init) {
+ int max = DEFAULT_MAX;
+
+ if (init != null) {
+ if (init instanceof Integer) {
+ max = ((Integer)init).intValue();
+ } else {
+ throw new IllegalArgumentException("init must be of type Integer");
+ }
+ }
+
+ _messages = new String[max];
+ _index = 0;
+ }
+
+ /**
+ * Nullifies array of log messages
+ * @see LogAdapter#destroy()
+ */
+ public void destroy() {
+ _index = -1;
+ _messages = null;
+ }
+
+ /**
+ * Put log message into message buffer. If the buffer is full, the oldest
+ * message is over writen.
+ * @see LogAdapter#log(java.lang.String, int)
+ */
+ public void log(String message, int level) {
+ _messages[_index] =
+ FMT.format(new Date())+" ["+Logger.levelToString(level)+"] "+message;
+
+ _index = (_index+1)%_messages.length;
+ }
+
+ /**
+ * Get the current contents of the message buffer starting with
+ * the oldest message.
+ * @return
+ */
+ public String dump() {
+ StringBuffer dump = new StringBuffer();
+
+ for (int i=0; i<_messages.length; i++) {
+ String msg = _messages[(_index+i)%_messages.length];
+ if (msg != null) dump.append(msg).append('\n');
+ }
+
+ return dump.toString();
+ }
+}
diff --git a/src/com/jiggak/log/adapter/StdoutAdapter.java b/src/com/jiggak/log/adapter/StdoutAdapter.java
new file mode 100644
index 0000000..a0d3573
--- /dev/null
+++ b/src/com/jiggak/log/adapter/StdoutAdapter.java
@@ -0,0 +1,26 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <josh@slashdev.ca> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return Josh Kropf
+ * ----------------------------------------------------------------------------
+ */
+package com.jiggak.log.adapter;
+
+import com.jiggak.log.LogAdapter;
+import com.jiggak.log.Logger;
+
+/**
+ * Sends log messages to standard output. This is really only useful
+ * when using a simulator since the device does not have standard output.
+ * @author Josh Kropf <josh@slashdev.ca>
+ */
+public final class StdoutAdapter extends LogAdapter {
+ public void create(Object init) { }
+ public void destroy() { }
+
+ public void log(String message, int level) {
+ System.out.println(Logger.levelToString(level)+" "+message);
+ }
+}