/*
* The MIT License
*
* Copyright 2012 Massive Dynamics.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package biz.massivedynamics.modger;
import biz.massivedynamics.modger.formatter.Formatter;
import biz.massivedynamics.modger.formatter.message.SingleLineMessageFormatter;
import biz.massivedynamics.modger.formatter.throwable.GenericThrowableFormatter;
import biz.massivedynamics.modger.message.Message;
import biz.massivedynamics.modger.message.MessageType;
import biz.massivedynamics.modger.message.filter.MessageFilter;
import biz.massivedynamics.modger.message.filter.impl.BlankMessageFilter;
import biz.massivedynamics.modger.message.filter.impl.MessageTypeFilter;
import biz.massivedynamics.modger.message.handler.MessageHandler;
import biz.massivedynamics.modger.message.handler.impl.SystemOutputMessageHandler;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A class that defines a single {@link Logger}
* <br />
* Each {@link Logger} that is constructed has its own set of properties, some of which are displayed below.
* <p>
* <h3>Name</h3>
* The logger's name is displayed on each message displayed. It is commonly used for easy identification.
* </p>
* <p>
* <h3>Message Formatter</h3>
* A "message formatter" is a {@link Formatter}, which formats a raw {@link Message} into another {@link Message} which is created on the fly.
* </p>
* <p>
* <h3>Throwable Formatter</h3>
* A "throwable formatter" is a {@link Formatter} which formats a raw {@link Throwable} into a formatted {@link String}.
* <br />
* The default formatter, {@link GenericThrowableFormatter}, includes a stack trace. If wanted, {@link biz.massivedynamics.modger.formatter.throwable.ShortThrowableFormatter} does not contain this.
* </p>
* <p>
* <h3>Message handlers</h3>
* Each {@link Logger} contains a number of {@link MessageHandler}s, which handle any {@link Message}s that are passed to it.
* <br />
* More about {@link Message}s can be found in the javadoc for that class.
* </p>
* <p>
* <h3>Message Filters</h3>
* Each {@link Logger} can contain a number of {@link MessageFilter}s. These help filter any {@link Message} that doesn't meet the logging requirements.
* <br />
* Loggers contain the following filters by default:
* <ul>
* <li>{@link BlankMessageFilter}</li>
* <li>{@link MessageTypeFilter}</li>
* </ul>
* </p>
*
*
* @author Cruz Bishop
* @since 1.0.0.0
*/
public class Logger implements Cloneable {
/**
* Creates an anonymous logger
*
* @since 1.0.0.0
*/
public Logger() {
this("Anonymous", new SingleLineMessageFormatter(), new GenericThrowableFormatter(), new SystemOutputMessageHandler());
}
/**
* Creates a new logger
*
* @param name The name to use
* @since 1.0.0.0
*/
public Logger(String name) {
this(name, new SingleLineMessageFormatter(), new GenericThrowableFormatter(), new SystemOutputMessageHandler());
}
/**
* Creates a logger with the specified message formatter
*
* @param name The name to use
* @param messageFormatter The message formatter to use
* @since 1.0.0.0
*/
public Logger(String name, Formatter<Message, Message> messageFormatter) {
this(name, messageFormatter, new GenericThrowableFormatter(), new SystemOutputMessageHandler());
}
/**
* Creates a logger with the specified formatters
*
* @param name The name to use
* @param messageFormatter The message formatter to use
* @param throwableFormatter The throwable formatter to use
* @since 1.0.0.0
*/
public Logger(String name, Formatter<Message, Message> messageFormatter,
Formatter<Throwable, String> throwableFormatter) {
this(name, messageFormatter, throwableFormatter, new SystemOutputMessageHandler());
}
/**
* Creates a logger with the specified message handlers and formatter
*
* @param name The name to use
* @param messageFormatter The message formatter to use
* @param handlers The message handlers to use
* @since 1.0.0.0
*/
public Logger(String name, Formatter<Message, Message> messageFormatter, MessageHandler... handlers) {
this(name, messageFormatter, new GenericThrowableFormatter(), new SystemOutputMessageHandler());
}
/**
* Creates a logger with the specified message handlers and formatter
*
* @param name The name to use
* @param messageFormatter The message formatter to use
* @param throwableFormatter The throwable formatter to use
* @param handlers The handlers to use
* @since 1.0.0.0
*/
public Logger(String name, Formatter<Message, Message> messageFormatter,
Formatter<Throwable, String> throwableFormatter,
MessageHandler... handlers) {
//Add the handlers
this.handlers.addAll(Arrays.asList(handlers));
//Set up the default filters
this.filters.add(new BlankMessageFilter());
this.filters.add(new MessageTypeFilter());
//Set the message formatter
this.messageFormatter = messageFormatter;
//Set the throwable formatter
this.throwableFormatter = throwableFormatter;
//Set the name
this.name = name;
}
/**
* The name to use when logging
*
* @since 1.0.0.0
*/
private String name;
/**
* Gets the name
*
* @return The name
* @since 1.0.0.0
*/
public String getName() {
return this.name;
}
/**
* Sets the name
*
* @param name The name to use
* @since 1.0.0.0
*/
public void setName(String name) {
this.name = name;
}
/**
* The list of {@link MessageHandler}s used by this {@link Logger}
* <br />
* Each {@link MessageHandler} will be passed a {@link Message}
*
* @since 1.0.0.0
*/
private ArrayList<MessageHandler> handlers = new ArrayList<>();
/**
* Gets the list of {@link MessageHandler}s used by this {@link Logger}
*
* @return The list of message handlers
* @since 1.0.0.0
*/
public ArrayList<MessageHandler> getHandlers() {
return this.handlers;
}
/**
* The list of {@link MessageFilter}s used by this {@link Logger}
* <br /><br />
* Each {@link MessageFilter} will be used to filter every submitted {@link Message}
*
* @since 1.0.0.0
*/
private ArrayList<MessageFilter> filters = new ArrayList<>();
/**
* Gets the list of {@link MessageFilter}s
*
* @return The filters
* @since 1.0.0.0
*/
public ArrayList<MessageFilter> getFilters() {
return this.filters;
}
/**
* The {@link Formatter} used to format {@link Message}s in this logger
*
* @since 1.0.0.0
*/
private Formatter<Message, Message> messageFormatter;
/**
* Gets the {@link Formatter} used to format {@link Message}s in this {@link Logger}
*
* @return The {@link Message} {@link Formatter}
* @since 1.0.0.0
*/
public Formatter<Message, Message> getMessageFormatter() {
return this.messageFormatter;
}
/**
* Sets the {@link Formatter} used to format {@link Message}s in this {@link Logger}
*
* @param formatter The {@link Formatter} to use
* @since 1.0.0.0
*/
public void setMessageFormatter(Formatter<Message, Message> formatter) {
this.messageFormatter = formatter;
}
/**
* The {@link Formatter} used to format {@link Throwable}s in this {@link Logger}
*
* @since 1.0.0.0
*/
private Formatter<Throwable, String> throwableFormatter;
/**
* Gets the {@link Formatter} used to format {@link Throwable}s in this {@link Logger}
* <br />
* Each {@link Throwable} is formatted into a {@link String}
*
* @return The {@link Throwable} {@link Formatter}
* @since 1.0.0.0
*/
public Formatter<Throwable, String> getThrowableFormatter() {
return this.throwableFormatter;
}
/**
* Sets the {@link Formatter} used to format {@link Throwable}s in this {@link Logger}
*
* @param formatter The {@link Formatter} to use
* @since 1.0.0.0
*/
public void setThrowableFormatter(Formatter<Throwable, String> formatter) {
this.throwableFormatter = formatter;
}
/**
* Submits a {@link Message} and attached {@link Throwable} cause to each {@link Messagehandler}
* <br />
* This includes filtering via {@link MessageFilter}s and a pass through the {@link Formatter}s
*
* @param message The {@link Message} to submit
* @param cause The {@link throwable} to also submit
* @since 1.0.0.0
*/
private void submitMessage(Message message, Throwable cause) {
for (MessageFilter filter : this.filters) {
//See if a filter deems that a message is unacceptable
if (!filter.isAcceptable(message)) {
//Nope. Return without doing anything!
return;
}
}
//Format the message
message.reformatMessage();
//Loop through each handler
for (MessageHandler handler : this.handlers) {
//Try to handle the message
try {
handler.submit(message, cause);
} catch (Exception e) {
//We can't really do anything
//except continue and hope that the message is handled.
//Sending another message could slip by a filter and cause an endless loop
//BAD!
continue;
}
}
}
/**
* Submits a {@link Message} to the registered {@link MessageHandler}s
* <br />
* This includes filtering via {@link MessageFilter}s and a pass through the
* {@link Message} {@link Formatter}
*
* @param message The {@link Message} to submit
* @since 1.0.0.0
*/
private void submitMessage(Message message) {
for (MessageFilter filter : this.filters) {
//See if a filter deems that a message is unacceptable
if (!filter.isAcceptable(message)) {
//Nope. Return without doing anything!
return;
}
}
//Format the message
message.reformatMessage();
//Loop through each handler
for (MessageHandler handler : this.handlers) {
//Try to handle the message
try {
handler.submit(message);
} catch (Exception e) {
//We can't really do anything
//except continue and hope that the message is handled.
//Sending another message could slip by a filter and cause an endless loop
//BAD!
continue;
}
}
}
/**
* Submits one or more trace {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitTrace(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.TRACE));
}
}
/**
* Submits a trace {@link Message} with an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The {@link Throwable} to use as a cause
* @since 1.0.0.0
*/
public void submitTrace(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.TRACE), throwable);
}
/**
* Submits one or more debug {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitDebug(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.DEBUG));
}
}
/**
* Submits a debug {@link Message} which has an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitDebug(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.DEBUG), throwable);
}
/**
* Submits one or more information {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitInformation(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.INFORMATION));
}
}
/**
* Submits an information {@link Message} with an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitInformation(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.INFORMATION), throwable);
}
/**
* Submits one or more regular {@link Message}s
*
* @param messages The {@link String} {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitMessage(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.REGULAR));
}
}
/**
* Submits a regular {@link Message} which has an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitMessage(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.REGULAR), throwable);
}
/**
* Submits one or more warning {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitWarning(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.WARNING));
}
}
/**
* Submits a warning {@link Message} which has an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitWarning(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.WARNING), throwable);
}
/**
* Submits one or more error {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.0.0.0
*/
public void submitError(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.ERROR));
}
}
/**
* Submits an error {@link Message} with an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitError(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.ERROR), throwable);
}
/**
* Submits one or more fatal error {@link Message}s
*
* @param messages The {@link Message}s to submit
* @since 1.1.1.0
*/
public void submitFatal(String... messages) {
for (String message : messages) {
this.submitMessage(new Message(this, message, MessageType.FATAL));
}
}
/**
* Submits a fatal error {@link Message} with an attached {@link Throwable} cause
*
* @param message The {@link Message} to submit
* @param throwable The attached {@link Throwable} cause
* @since 1.0.0.0
*/
public void submitFatal(String message, Throwable throwable) {
this.submitMessage(new Message(this, message, MessageType.FATAL), throwable);
}
/**
* Clones this {@link Logger}, but creates a new name
*
* @param name The name to use
* @return The new {@link Logger}
* @since 1.0.0.0
*/
public Logger clone(String name) {
//Clone this logger
Logger clonedLogger = this.clone();
//Set the name
clonedLogger.setName(name);
//And return the cloned logger
return clonedLogger;
}
/**
* Clones this {@link Logger}
*
* @return The cloned {@link Logger}
* @since 1.0.0.0
*/
@Override
public Logger clone() {
Logger clonedLogger = new Logger(this.getName(),
this.getMessageFormatter(),
this.getThrowableFormatter());
//Reset and set the handlers
clonedLogger.getHandlers().clear();
clonedLogger.getHandlers().addAll(this.getHandlers());
//Reset and set the filters
clonedLogger.getFilters().clear();
clonedLogger.getFilters().addAll(this.getFilters());
//And return the new logger
return clonedLogger;
}
}