A logging framework using the piping library.
How To
Load Verbose with ASDF or Quicklisp.
(ql:quickload :verbose)
Under normal circumstances, Verbose starts itself up automatically after you've loaded it, so you can dive right in and log things. You'll want to add a local nickname for verbose to use it easily though, such as v
, which we'll be using in this tutorial.
(defpackage #:my-package
(:use #:cl)
(:local-nicknames
(#:v #:org.shirakumo.verbose)))
(v:log :info :intro "Hello!")
You will notice that there are three pieces of information to every log message you send over Verbose. The level at which the message is logged, the category, and finally the message itself. For each of the standard v:*levels*
, a shorthand function trace
debug
info
warn
error
severe
fatal
exists.
(v:info :intro "Hello again.")
While the bulk of your logging will probably be made up by messages, you can log any kind of object. However, some classes receive special handling for convenience. Namely string
s, symbol
s, function
s, and condition
s. Strings in reality are format strings, and thus take an arbitrary number of extra arguments.
(v:info :intro "We are ~:[good to go~;not ready yet~]." NIL)
Similarly, symbols are taken as condition or class names and the rest of the arguments are used as class-initargs. This allows you to conveniently construct custom objects for logging.
(v:info :intro 'simple-error :format-control "Aw huckleberry!")
This will also show the special handling for conditions. When a condition object is logged, Verbose also immediately captures the stack at the current point and formats it as a backtrace when printed. You can control how much of a backtrace is shown, but you'll have to consider Dissect's documentation for that. If you don't like this much info for conditions, you can however also entirely disable it by setting *verbose-conditions*
to NIL
.
Finally, when logging function objects they are simply called with the rest of the arguments.
(v:info :intro #'1+ 1)
Verbose configures itself to only show messages from the info level and up to you at the REPL. You can change this behaviour by setting the v:repl-level
to whichever the lowest level you want to see should be.
(v:debug :intro "Snake, this is a stealth mission.")
(setf (v:repl-level) :debug)
(v:debug :intro "Hrnm... stealth...")
Aside from just being useful information, the categories can also be filtered. Normally all categories are allowed through, but you can limit this to only the categories that you want.
(setf (v:repl-categories) (list :woods))
(v:info :city "Lots of car noises")
(v:info :woods "Birds chirping")
But categories can go beyond that still. Categories are actually trees, if you separate each branch by a dot in the name. You can then filter by branch and only allow subbranches through.
(setf (v:repl-categories) (list :woods.cottage))
(v:info :woods "Birds still chirping")
(v:info :woods.cottage "Crashing sounds as a moose runs through")
As you can guess, you can have an arbitrary amount of categories that you want to see at the same time. If you want to see nothing at all, you set the categories to NIL
. If you want to see everything, you set it to T
. Juggling the category list can be a bit cumbersome like this though, so for convenience there are add-repl-category
and remove-repl-category
that each take a list of categories to add or remove at once.
(setf (v:repl-categories) T)
Aside from being trees, a message can also carry more than one category at the same time. This allows you to tailor what you want to see even more selectively. You can also stash away the categories you want to use in a variable so that you can easily reference them without having to write them all out, if it happens to become excessive.
(v:info '(:system :core.toolkit) "Deleting everything on disk...")
(defvar *cats* '(:noodles :trophy :keyboard))
(v:info *cats* "Meow.")
Before I get to the last point about categories, it is necessary to talk a bit about how Verbose works internally. In order to be extensible, a very generic backend is used that bases its ideas in pipelines. What we've used so far is one pipe segment that is automatically constructed for use at the REPL. It consists of a level-filter
, a category-tree-filter
, and a repl-faucet
. The first one only accepts messages of the correct level, the second one only those that match the categories, and the last one is responsible for printing the messages out.
Being extensible like this it allows you to construct any form of pipeline you might want that updates, filters, and finally records the messages as you desire. There is one more final piece to Verbose's system to be aware of. When the system is thread-capable, Verbose launches a background thread that is used to process messages. Whenever you call a logging function it puts it onto a queue and notifies the thread to process it. This is necessary in order to make logging from separate threads simultaneously possible without everything ending up as mangled garbage.
If you don't need to use threads in your application or want to log directly from the current thread, bypassing the background thread you can bind or set *process-locally*
to T
. Otherwise if you want to use the thread, but sometimes need to ensure that messages have been processed, you can make use of v:sync
which will block until all queued messages have been processed.
Finally we come to the last feature to do with categories. You can muffle categories locally, preventing messages with matching categories from being processed. This is an important difference to changing the REPL categories in that the message will never reach the pipeline to begin with. In the case of the REPL categories, other pipes may still process the message-- it just isn't printed to the REPL. You should only use muffling if you are absolutely sure that you do not want these messages to be processed at all.
(v:with-muffled-logging (:cars)
(v:info :pedestrians "Walking")
(v:info :cars "Honking")
(v:info '(:cars :pedestrians) "Exist"))
The with-muffled-logging
simply binds *muffled-categories*
, which is a list of muffled categories or T
for everything, just like for the category filter.
When deploying an application the background thread might again cause problems as it is started by default and dumping an image with threads alive is not possible. Thus, you should call stop
on *global-controller*
before dumping and start
after resuming the image. Alternatively you can push :verbose-no-init
onto *features*
before loading Verbose and then run start
manually.
If you are accessing your Lisp image from multiple SLIME instances and the *standard-output*
changes, you can use v:output-here
to make it pick up the current standard output value again. Similarly, if you want to redirect the REPL output to another stream, you can do so by setting the shared value.
(v:output-here (open #p"~/some-file.log" :direction :output))
However, if you really want to log to a file, you should see the following section for a proper solution.
Customising Verbose
Especially in production environments you'll likely want to do something more than simply logging to the REPL. This is where the aforementioned pipeline system comes in. Verbose offers a couple of standard pipe segments that should be sufficient for most purposes. If you need more than that, see the next section.
stream-faucet
Simply writes messages to a stream byformat-message
.repl-faucet
Inherits fromstream-faucet
and merely defaults the stream to*standard-output*
.file-faucet
Inherits fromstream-faucet
and just manages opening/closing the stream to the file.rotating-file-faucet
Inherits fromfile-faucet
, but rotates the log file to a new one in a specified interval. This is recommended for very long-running instances.category-filter
Only lets through messages of which one or more categories match the internalcategories
list.category-tree-filter
Inherits fromcategory-filter
, but filters tree-like by interpreting each category as a branch with dots separating the segments.level-filter
Only lets through messages which are on a level equal to or higher than thefiltered-level
.
What you'll most likely want to do is configure the controller to send messages through a new pipe that will end in a faucet.
(v:define-pipe ()
(v:rotating-file-faucet :template #p"verbose.log"))
This is the simplest you can get, and sufficient if you just want to dump literally everything to a file. If you want to filter things, you'll need to stick a filter segment before it.
(v:define-pipe ()
(v:level-filter :level :error)
(v:rotating-file-faucet :file #p"err.log"))
You can add as many pipes you want, and stick as many filters before each as you like. For cheap "one-time use" filters that need a bit more work than the level-filter and category-filters offer, you can use piping's predicate-filter
, which takes a predicate whose return value dictates whether the message should be let through.
(v:define-pipe ()
(piping:predicate-filter :predicate (lambda (m) (= 0 (local-time:timestamp-hour (v:timestamp m)))))
(v:rotating-file-faucet :file #p"midnight.log"))
As mentioned before, everything else will need custom segments, which are discussed in the next section.
Extending Verbose
On the most basic level you might want to customise how messages are printed. Since I don't expect there to be any intermediate libraries basing on Verbose, and instead it being usually used in an end-user application, the simplest way to get that done is to simply override the format-message
method.
(defmethod v:format-message ((stream stream) (message v:message))
(format stream "~&~a~%" (v:content message)))
If you don't like replacing code, you can instead subclass message
and set it as the default class.
(defclass my-message (v:message) ())
(defmethod v:format-message ((stream stream) (message my-message))
..)
(setf v:*default-message-class* 'my-message)
Doing the latter naturally also allows you to add more fields and other shenanigans. However, in order to actually fill those fields you will have to figure out shenanigans of your own, write log functions of your own that call out to log-message
with the desired initargs, or replace/extend the standard methods on log
to do what you need them to do.
Next you might want to create a filter pipe segment of your own that does more complex, or perhaps configurable filtering. In order to do this you will want to subclass piping:filter
and add a method to pass
. This method should return a message object --which may or may not be the same as the one it receives-- to be passed along further down the pipeline or NIL
if it should get blocked.
(defclass type-filter (piping:filter)
((type :initarg :type :initform T :accessor filter-type)))
(defmethod piping:pass ((filter type-filter) thing)
(when (typep thing (filter-type filter))
thing))
After adding the filter and a faucet to the pipeline as illustrated above, you'll likely want to get easy access to it again at a later point in order to be able to change its fields. To do this it pays off to give it a name. You can do this by adding a :name
field to your define-pipe
expression.
(v:define-pipe ()
(type-filter :name 'type-filter)
(v:repl-faucet))
After setting the name, you can retrieve your filter with find-place
.
(piping:find-place v:*global-controller* 'type-filter)
These very basic functions is pretty much all the magic that Verbose uses internally to provide you convenience functions like repl-level
and make-standard-global-controller
.
Building custom faucets that output to a database or some other medium that isn't supported by files follows about the same procedure as making a custom filter. You subclass piping:faucet
and add a method on pass
that does what you need it to do. Then you instantiate your class and add that to the pipeline.
If the logging levels provided by default are not sufficient for you and you'd like to add some or change them, you merely have to manipulate the *levels*
variable. It describes the priority as an integer with the associated symbol. Defining new ones is merely a matter of using add-level
. If you also would like a convenience function along with the standard levels, you can use define-level
for that.
(v:define-level -20 :whisper)
(v:whisper :somewhere "I'm a ghost.")
(v:add-level 100 'scream)
(v:log 'scream :somewhere "AAAA!!!")
Finally, if you need some more serious control over things and perhaps mess with the dispatch logic or something that I cannot really fathom right now, you might want to create your own controller type. A controller needs to implement a couple of methods in order to function. You will most likely be interested in changing pass
and controller-loop
. The first is responsible for scheduling the message onto the controller or directly executing it if that is not allowed (by *process-locally*
) or not possible. The second is responsible for doing whatever the background thread should be doing.
In the default implementation, pass
pushes the message onto a queue and then notifies a condition that should awake the controller thread. The controller thread then processes this queue by calling pass
on its pipeline (an array) and each object in the queue. There's some more mechanics involved in order to reduce the potential impact for waiting that complicate this, but in essence that's all that happens.
Also relevant might be start
and stop
which are responsible for setting up and tearing down any background mechanisms, if necessary. In the standard implementation this takes care of creating and shutting down the thread.
Upgrading from Verbose 1.x
Verbose was one of the very early libraries that I've written in my years of lisp. As such it had somewhat poor style, naming ideas, and plans on how to go about things. In an effort to make Verbose more generally useful and easier to approach I decided that it would be in the best interest to drop all the cruft and change things around somewhat liberally. This means that Verbose 2.0 is incompatible with the previous 1.x.
However, fear not. Most of the high-level interface is still the same. Logging works the same, the controller is in the same place and can be reset in the same way. Adding pipes still works as before. Things have mostly changed on the internals side, so if you did not extend or hack verbose extensively, you should be mostly fine.
One thing to note in particular though is that there is no rotating-log-faucet
anymore. It has been replaced by the rotating-file-faucet
, which no longer works on CRON intervals, but instead on a less-flexible, but easier to manage set of fixed intervals.
Other than that, I hope that the above documentation will serve as a good guide on how to replace the code that I have broken in the process. My apologies if you have been hit by this; I promise not to break things again in the near future.
Also See
System Information
Definition Index
-
ORG.SHIRAKUMO.VERBOSE
No documentation provided.-
EXTERNAL SPECIAL-VARIABLE *DEFAULT-MESSAGE-CLASS*
The class designator of the message class to use when logging messages.
-
EXTERNAL SPECIAL-VARIABLE *GLOBAL-CONTROLLER*
Stores the default controller. While it is possible to have multiple controllers, there is not much reason to do so. The pipeline system should be flexible enough to bypass the need for multiple controllers. However, you can still instantiate multiple controllers and manage them in whatever way you like. Just make sure to bind this variable to the appropriate one if the function does not accept the controller as an argument directly.
-
EXTERNAL SPECIAL-VARIABLE *LEVELS*
Holds the alist of priorities to level names. This list must be sorted in ascending order of priorities. See ADD-LEVEL See DEFINE-LEVEL
-
EXTERNAL SPECIAL-VARIABLE *MUFFLED-CATEGORIES*
Variable containing a list of categories that should get muffled upon issuing. If one of the categories is T, all messages are muffled. When a category is muffled, it is effectively removed from the message. If a message has no categories whatsoever, it is not issued. See WITH-MUFFLED-LOGGING
-
EXTERNAL SPECIAL-VARIABLE *PROCESS-LOCALLY*
Whether to process messages in the current thread. If this is T, then the messages will be shot through the pipeline in the thread whether the log statement is issued. This may be useful on systems where thread support is not necessary, but will most likely be less performant. If you really do not need to use threads, it is probably a better idea to simply shut down the controller's thread anyway. You can do this with STOP.
-
EXTERNAL SPECIAL-VARIABLE *TIMESTAMP-FORMAT*
The format in which timestamps will be formatted for messages. See LOCAL-TIME:FORMAT-TIMESTRING
-
EXTERNAL CLASS CATEGORY-FILTER
Only lets through messages that contain a category in the filter's categories list. CATEGORIES can be T in which case all messages are let through. See CATEGORIES See PIPING:FILTER
-
EXTERNAL CLASS CATEGORY-TREE-FILTER
Only lets through messages that match a category in the filter's category list. See MATCHING-TREE-CATEGORY See CATEGORY-FILTER
-
EXTERNAL CLASS CONDITION-MESSAGE
Message class to handle conditions being logged. See *VERBOSE-CONDITIONS* See MESSAGE-CONDITION
-
EXTERNAL CLASS CONTROLLER
This is the central piece that handles log messages. By default a background thread is spawned that processes the messages. You can control the thread with START and STOP and enqueue messages with PASS. You can prevent the controller from being automatically STARTed by passing :DONT-START T as an initarg. See THREAD See THREAD-CONTINUE See QUEUE See QUEUE-BACK See QUEUE-CONDITION See QUEUE-LOCK See START See STOP See PIPING:PASS
-
EXTERNAL CLASS FILE-FAUCET
A faucet that outputs to a file. See FILE See STREAM-FAUCET
-
EXTERNAL CLASS LEVEL-FILTER
Only lets through messages that are of the given level or higher. LEVEL can be either the name of a level in *LEVELS* or an integer of the appropriate size. See LEVEL See PIPING:FILTER
-
EXTERNAL CLASS MESSAGE
The base class for most logging messages that will be sent through the framework. See TIMESTAMP See THREAD See LEVEL See CATEGORIES See CONTENT See FORMAT-MESSAGE See LOG-MESSAGE
-
EXTERNAL CLASS REPL-FAUCET
A faucet that prints to the *standard-output*. See REPL-FAUCET
-
EXTERNAL CLASS ROTATING-FILE-FAUCET
No documentation provided. -
EXTERNAL CLASS STREAM-FAUCET
A faucet that prints the messages it receives to a stream. Messages are first passed through FORMAT-MESSAGE on the faucet itself, and then on the output stream. See OUTPUT See PIPING:FAUCET
-
EXTERNAL STRUCTURE SYNC-REQUEST
Struct to hold a request for synchronisation. When this object is processed by being passed down a vector it will first acquire and immediately release its lock and then notify its condition variable. The lock serves as a rendezvous point. See SYNC-REQUEST-CONDITION See SYNC-REQUEST-LOCK See SYNC
-
EXTERNAL FUNCTION ADD-LEVEL
- PRIORITY
- LEVEL
Adds or updates a level with the given priority and level. If a level with the requested name already exists, its priority is updated. Otherwise a new level is added. See *LEVELS*
-
EXTERNAL FUNCTION ADD-PIPE
- &REST
- SEGMENTS
Adds a new pipe to the controller. The first argument may be the controller object to modify. Constructs a pipe with the given segments as per MAKE-PIPE and INSERT, then finally adds the segment to the controller by ADD-SEGMENT.
-
EXTERNAL FUNCTION ADD-REPL-CATEGORY
- &REST
- CATEGORY
Convenience function to add more categories. The first argument may be the controller object to modify. See REPL-CATEGORIES
-
EXTERNAL FUNCTION DEBUG
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the DEBUG level.
-
EXTERNAL FUNCTION ERROR
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the ERROR level.
-
EXTERNAL FUNCTION FATAL
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the FATAL level.
-
EXTERNAL FUNCTION INFO
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the INFO level.
-
EXTERNAL FUNCTION LOG-MESSAGE
- LEVEL
- CATEGORIES
- CONTENT
- &OPTIONAL
- CLASS
- &REST
- INITARGS
Constructs a logging message and sends it off to be logged. See *DEFAULT-MESSAGE-CLASS* See LOG-OBJECT
-
EXTERNAL FUNCTION LOG-OBJECT
- OBJECT
Passes the given object to the global controller if it exists. See *GLOBAL-CONTROLLER* See PIPING:PASS
-
EXTERNAL FUNCTION MAKE-STANDARD-GLOBAL-CONTROLLER
- &REST
- INITARGS
Constructs a new controller object with a single pipe in the pipeline The pipe has a level-filter, category-tree-filter, and repl-faucet. All arguments to this function are simply passed as initargs to the construction of the CONTROLLER instance. See LEVEL-FILTER See CATEGORY-TREE-FILTER See REPL-FAUCET See CONTROLLER
-
EXTERNAL FUNCTION MATCHING-TREE-CATEGORY
- FILTER
- CATEGORY
This returns T if FILTER and CATEGORY are EQL or Both can be turned into sequences of items by splitting their SYMBOL-NAMEs on every occurrence of a period and each item in the list made from FILTER occurs in the same order at the beginning of the list made from CATEGORY. More simply put, if category is a sub-branch of filter, it passes the test.
-
EXTERNAL FUNCTION OUTPUT-HERE
- &OPTIONAL
- STANDARD-OUTPUT
- CONTROLLER
Modifies the standard repl faucet to output to the given stream. Also useful when the *STANDARD-OUTPUT* changes, such as in the case of SWANK and multiple connections to the same instance. See REPL-FAUCET
-
EXTERNAL FUNCTION REMOVE-GLOBAL-CONTROLLER
Stops and entirely removes the global controller, if present. See STOP See *GLOBAL-CONTROLLER*
-
EXTERNAL FUNCTION REMOVE-REPL-CATEGORY
- &REST
- CATEGORY
Convenience function to remove repl categories. The first argument may be the controller object to modify. See REPL-CATEGORIES
-
EXTERNAL FUNCTION REPL-CATEGORIES
- &OPTIONAL
- CONTROLLER
Accessor to the categories that will be printed at the REPL. See CATEGORY-TREE-FILTER See ADD-REPL-CATEGORY See REMOVE-REPL-CATEGORY
-
EXTERNAL FUNCTION (SETF REPL-CATEGORIES)
- CATEGORIES
- &OPTIONAL
- CONTROLLER
No documentation provided. -
EXTERNAL FUNCTION REPL-LEVEL
- &OPTIONAL
- CONTROLLER
Accessor to the current logging level that should be output to the REPL. See LEVEL-FILTER See *LEVELS*
-
EXTERNAL FUNCTION (SETF REPL-LEVEL)
- LEVEL
- &OPTIONAL
- CONTROLLER
No documentation provided. -
EXTERNAL FUNCTION RESTART-GLOBAL-CONTROLLER
Replaces the current global controller (if any) with a freshly allocated one. In case things really messed up somehow, this may resolve your problems at the cost of throwing away messages that are still queued up, and restoring the standard pipeline. See REMOVE-GLOBAL-CONTROLLER See *GLOBAL-CONTROLLER* See MAKE-STANDARD-GLOBAL-CONTROLLER
-
EXTERNAL FUNCTION SEVERE
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the SEVERE level.
-
EXTERNAL FUNCTION SYNC
- &OPTIONAL
- CONTROLLER
Blocks the current thread until all messages before this point have been processed. If the controller is not running a thread, this does nothing. Otherwise this is achieved by constructing and then passing a SYNC-REQUEST instance to the controller. See SYNC-REQUEST
-
EXTERNAL FUNCTION SYNC-REQUEST-CONDITION
- INSTANCE
Accessor to the condition variable for the sync request. See SYNC-REQUEST
-
EXTERNAL FUNCTION (SETF SYNC-REQUEST-CONDITION)
- VALUE
- INSTANCE
No documentation provided. -
EXTERNAL FUNCTION SYNC-REQUEST-LOCK
- INSTANCE
Accessor to the lock for the sync request. See SYNC-REQUEST
-
EXTERNAL FUNCTION (SETF SYNC-REQUEST-LOCK)
- VALUE
- INSTANCE
No documentation provided. -
EXTERNAL FUNCTION TRACE
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the TRACE level.
-
EXTERNAL FUNCTION WARN
- CATEGORIES
- DATUM
- &REST
- ARGS
Log to the WARN level.
-
EXTERNAL GENERIC-FUNCTION ANSI-COLORS
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION (SETF ANSI-COLORS)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION CATEGORIES
- OBJECT
The categories against which the object operates. See MESSAGE See CATEGORY-FILTER
-
EXTERNAL GENERIC-FUNCTION (SETF CATEGORIES)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION CONTENT
- OBJECT
The primary content that the message carries. Usually when the message is formatted, this will be printed by PRINC. See FORMAT-MESSAGE See MESSAGE
-
EXTERNAL GENERIC-FUNCTION (SETF CONTENT)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION CONTROLLER-LOOP
- CONTROLLER
Main function of the controller's background thread. Should handle message processing. This function should return when THREAD-CONTINUE is set to NIL. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION FILE
- OBJECT
Accessor to the file to which the faucet is currently outputting.
-
EXTERNAL GENERIC-FUNCTION (SETF FILE)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION FORMAT-MESSAGE
- STREAM
- MESSAGE
Formats the message according to the given thing. Standard implementations exist for NULL and STREAM. NULL will always return a string, and STREAM will print the message to the stream. You will want to extend or override methods on this to change the way messages are presented. See MESSAGE
-
EXTERNAL GENERIC-FUNCTION INTERVAL
- OBJECT
The interval in which the faucet's file is rotated. Can be one of :HOURLY :DAILY :MONTHLY :WEEKLY See ROTATING-LOG-FAUCET
-
EXTERNAL GENERIC-FUNCTION (SETF INTERVAL)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION LAST-ROTATION
- OBJECT
The universal-time timestamp of the last rotation. See ROTATE See ROTATING-LOG-FAUCET
-
EXTERNAL GENERIC-FUNCTION (SETF LAST-ROTATION)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION LEVEL
- OBJECT
The level at which the object operates. See *LEVELS* See MESSAGE See LEVEL-FILTER
-
EXTERNAL GENERIC-FUNCTION (SETF LEVEL)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION LOG
- LEVEL
- CATEGORIES
- DATUM
- &REST
- ARGS
Causes a message to be logged as appropriate for the given datum. By default, methods for STRING, SYMBOL, FUNCTION, and T exist. STRING --- The string is taken as a format string and the args as format arguments. SYMBOL --- The symbol is taken as condition or class name and a condition/class is constructed with the args as initargs. FUNCTION --- The function is wrapped in a lambda as a call with the arguments. This will then cause the function to get called during the processing of the message when FORMAT-MESSAGE is called. T --- The arguments are discarded and the datum is used as the CONTENT of the message. See LOG-MESSAGE
-
EXTERNAL GENERIC-FUNCTION MESSAGE-CONDITION
- OBJECT
Accessor to the condition that the message carries. See CONDITION-MESSAGE
-
EXTERNAL GENERIC-FUNCTION (SETF MESSAGE-CONDITION)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION OUTPUT
- OBJECT
The stream to which the stream-faucet outputs the messages. See STREAM-FAUCET
-
EXTERNAL GENERIC-FUNCTION (SETF OUTPUT)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION QUEUE
- OBJECT
The vector for the front message queue. In order to add messages to this queue, you should use VECTOR-PUSH-EXTEND wrapped in a WITH-CONTROLLER-LOCK. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION (SETF QUEUE)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION QUEUE-BACK
- OBJECT
The back queue for the controller. This is swapped with the front QUEUE when the controller decides to start processing messages. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION (SETF QUEUE-BACK)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION QUEUE-CONDITION
- OBJECT
The condition variable the controller will wait on until signalled. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION QUEUE-LOCK
- OBJECT
The lock to mutually exclude the controller thread and other threads from accessing the queues simultaneously. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION ROTATE
- FAUCET
- &OPTIONAL
- NEW-FILE
Causes the faucet to rotate to a new file immediately. See ROTATING-LOG-FAUCET
-
EXTERNAL GENERIC-FUNCTION START
- CONTROLLER
Starts the background thread of the controller. If there is no thread support, this does nothing. If there is already a thread active on the controller, a continuable error is signalled. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION STOP
- CONTROLLER
Stops the background thread of the controller. If there is no thread support, this does nothing. This function may take up to ~0.5s as it waits for the thread to exit on its own. If it still fails then, it will call BT:DESTROY-THREAD and hope that it will terminate properly. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION TEMPLATE
- OBJECT
The pathname serving as a template for the rotated files. See ROTATING-LOG-FAUCET
-
EXTERNAL GENERIC-FUNCTION (SETF TEMPLATE)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION THREAD
- OBJECT
Accessor to the thread held by the object. See CONTROLLER See MESSAGE
-
EXTERNAL GENERIC-FUNCTION (SETF THREAD)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION THREAD-CONTINUE
- OBJECT
Whether the controller thread should continue or not. See CONTROLLER
-
EXTERNAL GENERIC-FUNCTION (SETF THREAD-CONTINUE)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION TIMESTAMP
- OBJECT
The timestamp recorded from the time of issuing of the message. See LOCAL-TIME:TIMESTAMP See MESSAGE
-
EXTERNAL GENERIC-FUNCTION (SETF TIMESTAMP)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL MACRO DEFINE-LEVEL
- PRIORITY
- LEVEL
- &OPTIONAL
- NAME
Defines a new level by adding it and constructing a helper function. The helper function will automatically be exported, if its name is in the VERBOSE package (as it is by default). See ADD-LEVEL
-
EXTERNAL MACRO DEFINE-PIPE
- &OPTIONAL
- PIPELINE
- PLACE
- &BODY
- SEGMENTS
Shorthand convenience macro to define new pipes. SEGMENT ::= (class-name NAME? INITARG*) NAME ::= :name symbol INITARG ::= keyword value The optional name if given will be automatically assigned to the pipe segment, so that it can be retrieved through FIND-PLACE See PIPING:FIND-PLACE
-
EXTERNAL MACRO WITH-CONTROLLER-LOCK
- &OPTIONAL
- CONTROLLER
- &BODY
- FORMS
Evaluates FORMS with the controller's lock held. This will block until it can acquire the lock. See QUEUE-LOCK
-
EXTERNAL MACRO WITH-MUFFLED-LOGGING
- &OPTIONAL
- CATEGORY
- &REST
- MORE-CATEGORIES
- &BODY
- BODY
Adds the requested categories to the list of muffled categories. See *MUFFLED-CATEGORIES*
-
EXTERNAL SOURCE-TRANSFORM SYNC-REQUEST-CONDITION
No documentation provided. -
EXTERNAL SOURCE-TRANSFORM (SETF SYNC-REQUEST-CONDITION)
No documentation provided. -
EXTERNAL SOURCE-TRANSFORM SYNC-REQUEST-LOCK
No documentation provided. -
EXTERNAL SOURCE-TRANSFORM (SETF SYNC-REQUEST-LOCK)
No documentation provided.
-