Log

ILxLogService

class ILxLogService

The log service allows subsystems to be registered and walked.

Public Functions

LxResult ScriptQuery(LXtObjectID self, void **ppvObj)

As with all globals, the first method gets the ILxScriptQueryID interface for the system.

LxResult SubSystemCount(LXtObjectID self, unsigned int *count)

The list of subsystems can be walked with these functions. As of 901, an entry can only belong to one subsystem, or zero if it hasn’t been added to any yet.

LxResult SubSystemByIndex(LXtObjectID self, unsigned int index, void **ppvObj)
LxResult SubSystemLookup(LXtObjectID self, const char *name, void **ppvObj)

This looks up a subsystem by name or, if NULL, by ID.

LxResult MasterSubSystem(LXtObjectID self, void **ppvObj)
LxResult InfoBlockCount(LXtObjectID self, unsigned int *count)

Like subsystems, the list of info blocks can be walked and looked up by name.

LxResult InfoBlockByIndex(LXtObjectID self, unsigned int index, void **ppvObj)
LxResult InfoBlockLookup(LXtObjectID self, const char *name, void **ppvObj)

This looks up a subsystem by name.

LxResult InfoBlockFieldsAreSameGroup(LXtObjectID self, const char *name1, const char *name2)

These helpers check to see if two field names are in the same group (i.e., have the same name up to the first period), and return the names of the group and sub. The group test returns LXe_TRUE if the two field names are in the same group and LXe_FALSE if not. Any other code is an error.

LxResult InfoBlockFieldGetParts(LXtObjectID self, const char *name, const char **group, const char **sub)

This returns the group and/or sub parts of the field name. Either can be NULL if you only want the one. Note that *sub may be NULL if there is no sub. Also note that this function is NOT thread safe, and that the strings returned are only good until the next call to this function.

LxResult CreateEntryMessage(LXtObjectID self, LxResult type, const char *message, void **ppvObj)

Debug messages are used only for internal purposes, and follow the same visibility rules as DBprintf(), as well as being output to the console through DBprintf() when added.

LxResult CreateEntryInfoBlock(LXtObjectID self, LxResult type, const char *blockName, void **ppvObj)

Info blocks can be used to provide formatted messages. The first step is to get a new ILxLogEntryID with this method. The block arguments are the name of a previously registered info block. Once created, the ILxLogEntryID can be filled in with the the appropriate methods.

LxResult CreateEntryPaired(LXtObjectID self, LxResult type, void **ppvObj)

A second way to add complex formatted messages is through name/value pairs. The returned ILxLogEntryID will need to be populated with the appropriate methods.

LxResult SetMonitor(LXtObjectID self, LXtObjectID monitor)

There are times when high-level operations trigger low-level operations that may take a while. In that case we should have a monitor, but there is no way to pass the monitor down from the UI command to the actual code that needs it. The log service allows us to prepare a monitor and deliver it to a lower-level function. This method sets the global monitor. If called with null the monitor is cleared.

LXtObjectID AcquireMonitor(LXtObjectID self)

This method can be used by any low-level client to acquire the global monitor for use. The acquire method returns a “peek” of the global monitor, so it is not add-refed, and the method may return null if there is none or it has already been acquired previously.

LxResult EnableLogging(LXtObjectID self, const char *systemName, unsigned int state)

Logging can be enabled and disabled on a per-subsystem basis. When disabled, logged events will still go to that subsystem, but they will not show up in the master log or the console output. This does not affect rolling log entries.

LxResult IsLoggingEnabled(LXtObjectID self, const char *systemName)

This returns LXe_TRUE if loggin is enabled for a system, and LXe_FALSE if it is disabled.

LxResult CreateEntryMessageFromMsgObj(LXtObjectID self, LXtObjectID msgObj, void **ppvObj)

This allows yout create a new entry from an ILxMessageID. The message itself and the type code are read from the ILxMessageID

LxResult DebugLogOutput(LXtObjectID self, unsigned int level, const char *line)

This function lets plug-ins dump data to the normal debug log. The level indicates the severity of the information, allowing debug trace output to be hidden during normal usage.

LxResult DebugLogOutputSys(LXtObjectID self, unsigned int level, const char *logSystem, const char *line)
LXtObjectID ExceptionMessage(LXtObjectID self, LxResult error, unsigned flags)

The exception message is a single, global message object that holds a description of the cause of an unexpected failure. This can be set at the site of an initial error with a description of the cause of the error, and it will be displayed to the user by the controlling code higher up the stack. ExceptionMessage() grabs the exception message for this caller and returns it to allow it to be changed. Flags control the action to perform. Even if this exception isn’t the primary one it still gets captured for informational purposes. Since an exception mechanism that itself generates errors would be weird, this function will return null on errors which the client should check and do nothing.

LxResult ExceptionBlockStart(LXtObjectID self)

Exception messages are handled by a client system high enough to be able to display an error message, but general enough that any type of exception might be possible. The start method assures that past exceptions have been handled and clears the state. The collect method reads out any exception message. This generally only needs to be called when an error has happened, and if there is no error it will return NOTFOUND.

LxResult ExceptionBlockCollect(LXtObjectID self, void **ppvObj)
LxResult ReplaceEntryMessage(LXtObjectID self, LXtObjectID logEntry, LxResult type, const char *msg)

This low-level utility provides a way to change the string and type code associated with a message-class log entry. This is rarely used, but can be useful when you need to add some summary information to a parent entry. This only works on log entries created with CreateEntryMessage().


LXsLOG_LOGSYS

Any client can choose to log events with the log manager. Each client should register one subsystem name for each set of logged entry types it wants to have. You can register as many subsystems as you like, using each for different types of logging events. Any client can use any defined subsystem. Each registration is defined as an ILxLogID. The log system itself registers its own subsystem.


LXsSRV_LOGSUBSYSTEM

Subsystems are registered automatically simply by adding a tag to any server.


LXsLOG_MASTERSYS

There is also a special master subsystem. This is a combination of all logged entries, plus the most recently logged rolling entry. Entries cannot be directly added to this, but the ones that are there can be read in the normal manner.


LXe_LOG_DEBUG

Once registered, messages can be added to the log using simple strings. Each message will be added to both the master log and to the subsystem’s own internal log. These logs are stored as lists, with each new messages being added to the end of the list, and with old entries purged as needed. The type can be any LxResult code. LXe_INFO messages are relatively generic system states, such as a tooltip or confirmation that an operation has completed. LXe_WARNING and any LXx_FAIL() code designate non-fatal and fatal messages respectively. LXe_ABORT should be sent when an operation is aborted through a user action.

  • LXi_DBLOG_ERROR

  • LXi_DBLOG_NORMAL

  • LXi_DBLOG_TRACE

  • LXi_DBLOG_VERBOSE

  • LXfEXMSG_LOWLEVEL

  • LXfEXMSG_OVERRIDE

ILxLogInfoBlock

class ILxLogInfoBlock

Registering an info block requires an ILxLogInfoBlock object.

Public Functions

LxResult Name(LXtObjectID self, const char **name)

These return the name of the block.

LxResult FieldCount(LXtObjectID self, unsigned int *count)

This walks the list of fields, returning the total count and the name and datatype of each field. Note that FieldName() is NOT thread safe, and the returned string is only valid until the next call to this method.

LxResult FieldName(LXtObjectID self, unsigned int index, const char **name)
LxResult FieldType(LXtObjectID self, unsigned int index, const char **type)

ILxLog

class ILxLog

The log service allows subsystems to be registered and walked.

Public Functions

LxResult AddEntry(LXtObjectID self, LXtObjectID entry)

This adds an entry to a subsystem. Old entries will be dropped if needed. This does an AddRef() on the object, meaning you’ll still need to do your own release on it after it has been added.

LxResult RollEntry(LXtObjectID self, LXtObjectID entry)

It is also possible to create rolling messages. For example, it is not useful to log all of the Box Tool Info messages as described above; you really only want to see the current state of the Box Info Tool at any given time. A rolling message can be used to accomplish this. Another example is a context-sensitive status bar that provides specific information based on what the mouse is hovering over. This changes the rolling message. A separate rolling message is stored for each subsystem, with the one most recently changed being used as the master message.

LxResult RollClear(LXtObjectID self)

The rolling message can also be cleared when it is no longer needed.

LxResult EntryCount(LXtObjectID self, unsigned int *count)

Logged events specific to a particular subsystem can be scanned with these methods.

LxResult EntryByIndex(LXtObjectID self, unsigned int index, void **ppvObj)
LXtObjectID PeekEntryByIndex(LXtObjectID self, unsigned int index)

If you don’t want to or can’t release an entry, you can “peek” at the entry with this method. These entries should be considered volatile and should not be held onto for very long unless you AddRef them yourself.

LxResult GetCurrentEntry(LXtObjectID self, void **ppvObj)

The most recently added entry can be fetched with this function. This may be NULL if there is no recent entry.

LxResult SetMaxEntries(LXtObjectID self, unsigned int max)

The maximum number of entries that a particular subsystem can store can be set and read with these functions.

LxResult GetMaxEntries(LXtObjectID self, unsigned int *max)
LxResult GetRolling(LXtObjectID self, void **ppvObj)

The current rolling message can also be read. This returns LXe_NOTFOUND if there is currently no rolling entry.

LxResult ClearAll(LXtObjectID self)

This clears all entries from the subsystem. If called on the master subsystem, all subsystems are cleared.

LxResult Name(LXtObjectID self, const char **name)

The name of a subsystem can be returned at any time.

ILxLogEntry

class ILxLogEntry

A log entry contains a timestamp, an LxResult code and a message string. Log entries are owned by the subsystem and should not be released by the client.

Public Functions

LxResult AddEntry(LXtObjectID self, LXtObjectID entry)

Log entries can have child entries. A common child event is simply another message that provides more detail for the first, such as why an event failed. Normally the root event is a warning or error, with one or more child messages describing exactly why this occured. Info messages may also have children, providing more details on what might be an otherwise simple statement. Note that this only applies to simple messages, and not to complex data such as info blocks and name/value pairs. This does an AddRef() on the object, meaning you’ll still need to do your own release on it after it has been added. A log entry can have multiple parents, and will thus appear as a child of each parent. Care should be taken to avoid loops.

LxResult SetTitle(LXtObjectID self, const char *title)

This sets a title that can appear at the top of the block, which in this case is “Box (Squared)”.

LxResult SetDesc(LXtObjectID self, const char *desc)

This sets a description, which here is the three lines of text at the bottom of the block.

LxResult SetValue(LXtObjectID self, const char *name, unsigned int index, LXtObjectID value)

This sets the value of one of the fields in the info block. The specific field can be specified by either it’s name or it’s index, if the name is NULL. A matching ILxValueID must be provided for the field.

LxResult AddPair(LXtObjectID self, const char *name, const char *value)

SetDesc() can again be used to add a description after the pairs. This function can be used to add a pair of strings to the message.

LxResult Class(LXtObjectID self, unsigned int *classType)
LxResult Type(LXtObjectID self, LxResult *type)

The type can be returned as an LxResult code.

LxResult Time(LXtObjectID self, time_t *time)

The time at which the entry was logged can be read either as a C-style time_t or as a string via asctime().

LxResult TimeString(LXtObjectID self, const char **string)
LxResult ChildCount(LXtObjectID self, unsigned int *count)

The list of child entries for MESSAGE class entries can be enumerated with these methods.

LxResult ChildByIndex(LXtObjectID self, unsigned int index, void **ppvObj)
LXtObjectID PeekChildByIndex(LXtObjectID self, unsigned int index)

A peek method is also available.

LxResult SubSystemCount(LXtObjectID self, unsigned int *count)

Each root-level entry knows what subsystems it has been added to.

LxResult SubSystemByIndex(LXtObjectID self, unsigned int index, void **ppvObj)
LxResult Message(LXtObjectID self, const char **message)

The message stored in a MESSAGE-type log entry can be read out with this function. This fails if used on a non-MESSAGE type.

LxResult Title(LXtObjectID self, const char **title)

The title and description stored in a block-type log entry can be read out with these functions. These fail if used on a MESSAGE entry. Desc() can also be used on pairs, but not on MESSAGEs.

LxResult Desc(LXtObjectID self, const char **desc)
LxResult InfoBlock(LXtObjectID self, void **ppvObj)

This returns the info block definition.

LxResult InfoBlockValue(LXtObjectID self, const char *name, unsigned int index, void **ppvObj)

The ILxValueID for a particular field in the block can be extracted with this method. The value should be freed by the client when no longer needed. The field can be referenced by index or by name.

LxResult PairCount(LXtObjectID self, unsigned int *count)

These mehtods return the number of pairs, and the name and value strings by index.

LxResult PairName(LXtObjectID self, unsigned int index, const char **name)
LxResult PairValue(LXtObjectID self, unsigned int index, const char **value)

LXiLOGCLASS_MESSAGE

The various properties of an entry can be read with these functions. The class of the entry wuill be one of the following, depending on how the entry was created:

  • LXiLOGCLASS_BLOCK

  • LXiLOGCLASS_PAIRS

ILxLogListener

class ILxLogListener

The log listener can be used to listen for newly added log entries.

Public Functions

void SystemAdded(LXtObjectID self, LXtObjectID system)

This is called when a new log subsystem (ILxLogID) has been added to the application.

void EntryAdded(LXtObjectID self, LXtObjectID system, LXtObjectID entry)

Called when a new log entry is added to a subsystem. Note that a single log entry many belong to multiple subsystems.

void ChildEntryAdded(LXtObjectID self, LXtObjectID entry, LXtObjectID parentEntry)

Called when a new entry was added as a child of anohter log entry. This is only sent for root entries.

void EntryDropped(LXtObjectID self, LXtObjectID system, LXtObjectID entry)

Called when an entry has been dropped from the log, usually because the number of entries exceeds te maximum number allowed, and thus the oldest entry is removed.

void RollingEntryAdded(LXtObjectID self, LXtObjectID system, LXtObjectID entry)

Rolling log entries are much the same as normal logged entries. Since rolling logs only contain a single entry, RollingEntryAdded() implies RollingEntryDrop(). RollingEntryDrop() will still be called when the rolling log is cleared.

void RollingChildEntryAdded(LXtObjectID self, LXtObjectID entry, LXtObjectID parentEntry)
void RollingEntryDropped(LXtObjectID self, LXtObjectID system, LXtObjectID entry)