L
- The Logger
type to be supported. As the
AbstractCompositeLogger
is being extended to support other
Logger
types, we have to provide this generic parameter (for
example, sub-classes make use of the getLoggers()
method to
access the encapsulated Logger
instances being sub-types of
the Logger
interface).T
- The type of the Record
instances managed by the
Logger
.public abstract class AbstractCompositeLogger<L extends Logger<T>,T> extends Object implements Logger<T>, org.refcodes.component.Destroyable
CompositeLoggerImpl
uses the composite
pattern to forward logger functionality to a number encapsulated logger
instances. Depending on the performance (and availability) of an encapsulated
logger, the calls to the composite's #log(Record) method are executed by the
next encapsulated logger ready for execution.
An invocation of the
log(org.refcodes.tabular.Record)
method is forwarded to exactly one of the encapsulated
Logger
instances. The actual instance being
called depends on its availability (in case, partitioning is needed, take a
look at the PartedLoggerImpl
and its
sub-classes).
Using the CompositeLoggerImpl
, a huge
number of Record
instances can be logged in
parallel by logging them to different physical data sinks (represented by the
encapsulated logger instances), thereby avoiding a bottleneck which a single
physical data sink would cause for logging.
Internally a log line queue (holding Record
instances to be logged) as well a daemon thread per encapsulated logger
(taking elements from the log line queue) are used to decouple the
encapsulated logger instances from the
CompositeLoggerImpl
.
A given number of retries are approached in case there is an overflow of the
log line queue; this happens when the queue is full and there are none
encapsulated logger instances to take the next
Record
.
To avoid a building up of the log line queue, eventually causing an out of
memory, log lines not being taken into the log line queue (as it is full)
within the given number of retries, them log lines are dismissed. In such a
case a warning with a log-level WARN is printed out.
TODO: The CompositeLoggerImpl
could implement observable
functionality as of the "refcodes-observer" artifact; firing events when the
log lines queue grows near its limits - action then can be taken to add
loggers to the CompositeLoggerImpl
. Also when the log line queue
shrinks, loggers could be removed from the CompositeLoggerImpl
(important in cloud environments where resources cost real money).
TODO: Provide configuration parameters (additional constructors) for not
dismissing any log lines with the risk of a memory overflow. Also we might
provide parameters in additional constructors specifying minimum and maximum
number of endpoints; depending on the fill level of the log line queue, the
number of encapsulated Logger
instances might get increased (then we
need a LoggerFactory
also being provided) or decreased.
CompositeLoggerImpl
Constructor and Description |
---|
AbstractCompositeLogger(ExecutorService aExecutorService,
L... aLoggers)
Constructs an
AbstractCompositeLogger from the provided
Logger instances. |
AbstractCompositeLogger(L... aLoggers)
Constructs an
AbstractCompositeLogger from the provided
Logger instances. |
Modifier and Type | Method and Description |
---|---|
void |
destroy() |
protected Collection<L> |
getLoggers() |
void |
log(org.refcodes.tabular.Record<? extends T> aRecord)
Logs a
Record . |
@SafeVarargs public AbstractCompositeLogger(L... aLoggers)
AbstractCompositeLogger
from the provided
Logger
instances.aLoggers
- The Logger
instances to be used for the
AbstractCompositeLogger
.@SafeVarargs public AbstractCompositeLogger(ExecutorService aExecutorService, L... aLoggers)
AbstractCompositeLogger
from the provided
Logger
instances.aExecutorService
- The ExecutorService
to use when creating
threads.aLoggers
- The Logger
instances to be used for the
AbstractCompositeLogger
.public void log(org.refcodes.tabular.Record<? extends T> aRecord) throws IllegalRecordRuntimeException, UnexpectedLogRuntimeException
Logger
Record
. The targeted data sink for the Record
instances (where them are physically stored) depends on the
implementation of the Logger
. It can be a console, a file, a
stream or a database.log
in interface Logger<T>
aRecord
- The Record
to be logged.IllegalRecordRuntimeException
- Thrown in case the record cannot be
logged as a specific implementation might expect some dedicated
Column
instances to be contained in the provided Record.UnexpectedLogRuntimeException
- Thrown in case some other problems
regarding logging occurred, e.g. the data sink (physical system
where to log to) experiences problems.public void destroy()
destroy
in interface org.refcodes.component.Destroyable
protected Collection<L> getLoggers()
Copyright © 2016. All rights reserved.