Log (lx-log.hpp)
Contents
- 1 ILxLogService
- 1.1 (1) SDK: LXu_LOGSERVICE, etc. defines
- 1.2 (2) SDK: LogService::ScriptQuery
- 1.3 Subsystem Registration
- 1.4 Info Block Registration
- 1.5 Creating Entires
- 1.6 Low-level Monitor
- 1.7 Disabling and Enabling Logging
- 1.8 nexus 501
- 1.8.1 (29) SDK: LogService::CreateEntryMessageFromMsgObj
- 1.8.2 (30) SDK: CLxUser_LogService::NewEntryFromMsgObj method
- 1.8.3 (31) SDK: LogService::DebugLogOutput
- 1.8.4 (32) SDK: LogService::DebugLogOutputSys
- 1.8.5 (33) SDK: LXi_DBLOG_ERROR, etc. defines
- 1.8.6 (34) SDK: CLxUser_LogService::DebugOut method
- 1.8.7 (35) SDK: CLxUser_LogService::DebugOutSys method
- 1.9 nexus 801
- 1.10 nexus 801
- 2 ILxLogInfoBlock
- 3 ILxLog
- 4 ILxLogEntryID
- 4.1 (62) SDK: LXu_LOGENTRY, etc. defines
- 4.2 Simple Messages
- 4.3 Info Blocks
- 4.4 Name/Value Pairs
- 4.5 Properties
- 4.5.1 (70) SDK: LXiLOGCLASS_MESSAGE, etc. defines
- 4.5.2 (71) SDK: LogEntry::Class
- 4.5.3 (72) SDK: LogEntry::Type
- 4.5.4 (73) SDK: LogEntry::Time
- 4.5.5 (74) SDK: LogEntry::TimeString
- 4.5.6 (75) SDK: LogEntry::ChildCount
- 4.5.7 (76) SDK: LogEntry::ChildByIndex
- 4.5.8 (77) SDK: LogEntry::PeekChildByIndex
- 4.5.9 (78) SDK: LogEntry::SubSystemCount
- 4.5.10 (79) SDK: LogEntry::SubSystemByIndex
- 4.5.11 Messages
- 4.5.12 Info Blocks
- 4.5.13 Name/Value Pairs
- 5 Threaded Support
- 6 Log Listener
ILxLogService
The log service allows subsystems to be registered and walked.
(1) SDK: LXu_LOGSERVICE, etc. defines
#define LXu_LOGSERVICE "0BC355C2-5E6B-49EF-B368-600D9F26F543" #define LXa_LOGSERVICE "logservice"
As with all globals, the first method gets the ILxScriptQueryID interface for the system.
(2) SDK: LogService::ScriptQuery
LXxMETHOD( LxResult, ScriptQuery) ( LXtObjectID self, void **ppvObj);
Subsystem Registration
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.
(3) SDK: LXsLOG_LOGSYS define
#define LXsLOG_LOGSYS "logsys"
Subsystems are registered automatically simply by adding a tag to any server.
(4) SDK: LXsSRV_LOGSUBSYSTEM define
#define LXsSRV_LOGSUBSYSTEM "server.logsubsystem"
Since a tag can only be defined once per server, the string associated with the tag is a space-delimited list of subsystems to define. Slashes can be used to define categories that group subsystems. Note that the group name is considered part of the subsystems name, and as such must be included when doing lookusp on the name.
(5) SDK: Log Subsystem Define Server Tag Example
// Define a single subsystem const char *oneSubSystem = "mySubSystem"; // Define multiple subsystems in groups const char *multipleSubSystems = "group1/mySubSystem group2/subGroup/anotherSubSystem";
Enumeration
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.
(6) SDK: LogService::SubSystemCount
LXxMETHOD( LxResult, SubSystemCount) ( LXtObjectID self, unsigned int *count);
(7) SDK: LogService::SubSystemByIndex
LXxMETHOD( LxResult, SubSystemByIndex) ( LXtObjectID self, unsigned int index, void **ppvObj);
This looks up a subsystem by name or, if NULL, by ID.
(8) SDK: LogService::SubSystemLookup
LXxMETHOD( LxResult, SubSystemLookup) ( LXtObjectID self, const char *name, void **ppvObj);
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.
(9) SDK: LXsLOG_MASTERSYS define
#define LXsLOG_MASTERSYS "master"
(10) SDK: LogService::MasterSubSystem
LXxMETHOD( LxResult, MasterSubSystem) ( LXtObjectID self, void **ppvObj);
The user class has methods for getting subsystems by index or by name.
(11) SDK: CLxUser_LogService::GetSubSystem method
bool GetSubSystem ( unsigned index, CLxLoc_Log &sys) { LXtObjectID obj; if (LXx_FAIL (SubSystemByIndex (index, &obj))) return false; return sys.take (obj); } bool GetSubSystem ( const char *name, CLxLoc_Log &sys) { LXtObjectID obj; if (LXx_FAIL (SubSystemLookup (name, &obj))) return false; return sys.take (obj); }
Info Block Registration
Besides simple string-based message logging, it is also possible to log more formated infromation.. An example would be the status of the box tool, which could include the coordinates of two of the box's corners. However, this information is less than useful unless other systems know how to deal with the information provided.
To help with this problem, clients define an object with an ILxLogInfoBlock interface. The name and datatype are used to construct a block of information for display to the user. The name can include periods to group common properties.
For example, the corners of the box consists of one value for each axis, totaling three values for each corner, or six to define an entire box. If there is enough room, this might be displayed as six separate lines with one value each. If there isn't enough room for all six lines, the display could compensate by displaying one line each for each corner by combining all of the subnames for a particular name on the same line. If not needed, the subname can be set to NULL.
In the case of a box, we might have low.x, low.y and low.z for one corner, and high.x, high.y and high.z for the other corner, each defined to use the distance exotype.
Strings defined in the config file and uireg can be used to get user-readable names for these definitions. The actual layout in the log view is dependant on the available space
(12) Box Tool Info with maximum available space
Box Low X: -1.0 m Y: -1.0 m Z: -1.0 m High X: 1.0 m Y: 1.0 m Z: 1.0 m
(13) Box Tool Info with less than optimal space
Box Low X, Y, Z: -1.0 m, -1.0 m, -1.0 m High X, Y, Z: 1.0 m, 1.0 m, 1.0 m
(14) Box Tool Info with minimal vertical space
Box Low X, Y, Z: -1.0 m, -1.0 m, -1.0 m -- High X, Y, Z: 1.0 m, 1.0 m, 1.0 m
Info blocks are registered simply by defining a plug-in using the ILxLogInfoBlock interface. Once defined, any subsystem can use them to format their data. This fails if the name is already registered.
Enumeration
Like subsystems, the list of info blocks can be walked and looked up by name.
(15) SDK: LogService::InfoBlockCount
LXxMETHOD( LxResult, InfoBlockCount) ( LXtObjectID self, unsigned int *count);
(16) SDK: LogService::InfoBlockByIndex
LXxMETHOD( LxResult, InfoBlockByIndex) ( LXtObjectID self, unsigned int index, void **ppvObj);
This looks up a subsystem by name.
(17) SDK: LogService::InfoBlockLookup
LXxMETHOD( LxResult, InfoBlockLookup) ( LXtObjectID self, const char *name, void **ppvObj);
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.
(18) SDK: LogService::InfoBlockFieldsAreSameGroup
LXxMETHOD( LxResult, InfoBlockFieldsAreSameGroup) ( LXtObjectID self, const char *name1, const char *name2);
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.
(19) SDK: LogService::InfoBlockFieldGetParts
LXxMETHOD( LxResult, InfoBlockFieldGetParts) ( LXtObjectID self, const char *name, const char **group, const char **sub);
Creating Entires
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.
(20) SDK: LXe_LOG_DEBUG define
#define LXe_LOG_DEBUG LXxGOODCODE(LXeSYS_LOG,1)
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.
(21) SDK: LogService::CreateEntryMessage
LXxMETHOD( LxResult, CreateEntryMessage) ( LXtObjectID self, LxResult type, const char *message, 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.
(22) SDK: LogService::CreateEntryInfoBlock
LXxMETHOD( LxResult, CreateEntryInfoBlock) ( LXtObjectID self, LxResult type, const char *blockName, 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.
(23) SDK: LogService::CreateEntryPaired
LXxMETHOD( LxResult, CreateEntryPaired) ( LXtObjectID self, LxResult type, void **ppvObj);
After an entry has been created and filled in, it can be added to a subsystem using ILxLog::AddEntry() or ILxLog::RollEntry(). Message entries can be added as children of other message entries via ILxLogEntry::AddEntry(). Note that the AddEntry() and RollEntry() methods do their own AddRef(). This allows the same message to be added to multiple subsystems, but also means that you must release the object you created when you are done with it.
The C++ user classes methods get new entries and stores them in our user wrappers. These new COM objects are take()en by the CLxLoc_LogEntry(), and thus will automatically be released when the C++ class's destructor is called; you do NOT have to explicitly release their COM objects unless you explicitly AddRef()ed them.
(24) SDK: CLxUser_LogService::NewEntry method
bool NewEntry ( LxResult type, const char *message, CLxLoc_LogEntry &entry) { LXtObjectID obj; if (LXx_FAIL (CreateEntryMessage (type, message, &obj))) return false; return entry.take (obj); } bool NewBlockEntry ( LxResult type, const char *name, CLxLoc_LogEntry &entry) { LXtObjectID obj; if (LXx_FAIL (CreateEntryInfoBlock (type, name, &obj))) return false; return entry.take (obj); } bool NewPairEntry ( LxResult type, CLxLoc_LogEntry &entry) { LXtObjectID obj; if (LXx_FAIL (CreateEntryPaired (type, &obj))) return false; return entry.take (obj); }
Low-level 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.
(25) SDK: LogService::SetMonitor
LXxMETHOD( LxResult, SetMonitor) ( LXtObjectID self, LXtObjectID monitor);
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.
(26) SDK: LogService::AcquireMonitor
LXxMETHOD( LXtObjectID, AcquireMonitor) ( LXtObjectID self);
Disabling and Enabling Logging
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.
(27) SDK: LogService::EnableLogging
LXxMETHOD( LxResult, EnableLogging) ( LXtObjectID self, const char *systemName, unsigned int state);
This returns LXe_TRUE if loggin is enabled for a system, and LXe_FALSE if it is disabled.
(28) SDK: LogService::IsLoggingEnabled
LXxMETHOD( LxResult, IsLoggingEnabled) ( LXtObjectID self, const char *systemName);
nexus 501
This allows yout create a new entry from an ILxMessageID. The message itself and the type code are read from the ILxMessageID
(29) SDK: LogService::CreateEntryMessageFromMsgObj
LXxMETHOD( LxResult, CreateEntryMessageFromMsgObj) ( LXtObjectID self, LXtObjectID msgObj, void **ppvObj);
(30) SDK: CLxUser_LogService::NewEntryFromMsgObj method
bool NewEntryFromMsgObj ( CLxLoc_Message &message, CLxLoc_LogEntry &entry) { LXtObjectID obj; if (LXx_FAIL (CreateEntryMessageFromMsgObj (message, &obj))) return false; return entry.take (obj); }
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.
(31) SDK: LogService::DebugLogOutput
LXxMETHOD( LxResult, DebugLogOutput) ( LXtObjectID self, unsigned int level, const char *line);
(32) SDK: LogService::DebugLogOutputSys
LXxMETHOD( LxResult, DebugLogOutputSys) ( LXtObjectID self, unsigned int level, const char *logSystem, const char *line);
(33) SDK: LXi_DBLOG_ERROR, etc. defines
#define LXi_DBLOG_ERROR 1 #define LXi_DBLOG_NORMAL 2 #define LXi_DBLOG_TRACE 3 #define LXi_DBLOG_VERBOSE 4
Be careful when using DebugOut() and DebugOutSys(), as large strings will overflow the 1k buffers. You can increase the size of these buffers if necessary.
(34) SDK: CLxUser_LogService::DebugOut method
bool DebugOut ( unsigned int level, const char *format, ...) { char buf[1024]; va_list marker; va_start (marker, format); vsprintf (buf, format, marker); va_end (marker); return LXx_OK (DebugLogOutput (level, buf)); }
(35) SDK: CLxUser_LogService::DebugOutSys method
bool DebugOutSys ( unsigned int level, const char *logSystem, const char *format, ...) { char buf[1024]; va_list marker; va_start (marker, format); vsprintf (buf, format, marker); va_end (marker); return LXx_OK (DebugLogOutputSys (level, logSystem, buf)); }
nexus 801
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.
(36) SDK: LogService::ExceptionMessage
LXxMETHOD( LXtObjectID, ExceptionMessage) ( LXtObjectID self, LxResult error, unsigned flags);
LOWLEVEL | Marks this as a low-level description that should be overridden by any later (presumably more useful) description. |
OVERRIDE | Explicitly overriding any previous message. |
(37) SDK: LXfEXMSG_LOWLEVEL, etc. defines
#define LXfEXMSG_LOWLEVEL 0x01 #define LXfEXMSG_OVERRIDE 0x02
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.
(38) SDK: LogService::ExceptionBlockStart
LXxMETHOD( LxResult, ExceptionBlockStart) ( LXtObjectID self);
(39) SDK: LogService::ExceptionBlockCollect
LXxMETHOD( LxResult, ExceptionBlockCollect) ( LXtObjectID self, void **ppvObj);
nexus 801
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().
(40) SDK: LogService::ReplaceEntryMessage
LXxMETHOD( LxResult, ReplaceEntryMessage) ( LXtObjectID self, LXtObjectID logEntry, LxResult type, const char *msg);
Empty log service Python user class.
(41) PY: empty Service.Log user class
pass
ILxLogInfoBlock
Registering an info block requires an ILxLogInfoBlock object.
(42) SDK: LXu_LOGINFOBLOCK, etc. defines
#define LXu_LOGINFOBLOCK "B9AEE11A-3501-4dc2-90A6-41F2435856C6" #define LXa_LOGINFOBLOCK "loginfoblock"
These return the name of the block.
(43) SDK: LogInfoBlock::Name
LXxMETHOD( LxResult, Name) ( LXtObjectID self, const char **name);
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.
(44) SDK: LogInfoBlock::FieldCount, etc.
LXxMETHOD( LxResult, FieldCount) ( LXtObjectID self, unsigned int *count); LXxMETHOD( LxResult, FieldName) ( LXtObjectID self, unsigned int index, const char **name); LXxMETHOD( LxResult, FieldType) ( LXtObjectID self, unsigned int index, const char **type);
Empty LogInfoBlock Python user class.
(45) PY: empty LogInfoBlock user class
pass
ILxLog
A log subsystem manages it's individual entries. These objects are owned by the log system and should not be released by clients.
(46) SDK: LXu_LOG, etc. defines
Adding Entries
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.
(47) SDK: Log::AddEntry
LXxMETHOD( LxResult, AddEntry) ( 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.
(48) SDK: Log::RollEntry
LXxMETHOD( LxResult, RollEntry) ( LXtObjectID self, LXtObjectID entry);
The rolling message can also be cleared when it is no longer needed.
(49) SDK: Log::RollClear
LXxMETHOD( LxResult, RollClear) ( LXtObjectID self);
Enumeration
Logged events specific to a particular subsystem can be scanned with these methods.
(50) SDK: Log::EntryCount
LXxMETHOD( LxResult, EntryCount) ( LXtObjectID self, unsigned int *count );
(51) SDK: Log::EntryByIndex
LXxMETHOD( LxResult, EntryByIndex) ( LXtObjectID self, unsigned int index, void **ppvObj );
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.
(52) SDK: Log::PeekEntryByIndex
LXxMETHOD( LXtObjectID, PeekEntryByIndex) ( LXtObjectID self, unsigned int index );
The most recently added entry can be fetched with this function. This may be NULL if there is no recent entry.
(53) SDK: Log::GetCurrentEntry
LXxMETHOD( LxResult, GetCurrentEntry) ( LXtObjectID self, void **ppvObj );
The maximum number of entries that a particular subsystem can store can be set and read with these functions.
(54) SDK: Log::SetMaxEntries
LXxMETHOD( LxResult, SetMaxEntries) ( LXtObjectID self, unsigned int max );
(55) SDK: Log::GetMaxEntries
LXxMETHOD( LxResult, GetMaxEntries) ( LXtObjectID self, unsigned int *max );
The current rolling message can also be read. This returns LXe_NOTFOUND if there is currently no rolling entry.
(56) SDK: Log::GetRolling
LXxMETHOD( LxResult, GetRolling) ( LXtObjectID self, void **ppvObj );
This clears all entries from the subsystem. If called on the master subsystem, all subsystems are cleared.
(57) SDK: Log::ClearAll
LXxMETHOD( LxResult, ClearAll) ( LXtObjectID self );
The name of a subsystem can be returned at any time.
(58) SDK: Log::Name
LXxMETHOD( LxResult, Name) ( LXtObjectID self, const char **name );
User Methods
An alternate constructor for the subsystem allows the name to be specified. Or later, of you prefer.
(59) SDK: CLxUser_Log::CLxUser_Log method
CLxUser_Log ( const char *name) { _init (); setByName (name); } bool setByName ( const char *name) { CLxLoc_LogService svc; LXtObjectID obj; if (LXx_FAIL (svc.SubSystemLookup (name, &obj))) return false; return take (obj); }
For the most common case of a single text message we also have a user method to make that easy. Be sure to watch your string length due to the 1k buffer. You can increase the size of this buffer if necessary.
(60) SDK: CLxUser_Log::Message method
bool Message ( LxResult type, const char *format, ...) { CLxLoc_LogService svc; CLxLoc_LogEntry entry; LXtObjectID obj; char buf[1024]; va_list marker; va_start (marker, format); vsprintf (buf, format, marker); va_end (marker); if (LXx_FAIL (svc.CreateEntryMessage (type, buf, &obj))) return false; if (!entry.take (obj)) return false; return LXx_OK (AddEntry (entry)); } bool Info ( const char *text) { return Message (LXe_INFO, text); } bool Warn ( const char *text) { return Message (LXe_WARNING, text); }
Empty Log Python user class.
(61) PY: empty Log user class
pass
ILxLogEntryID
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.
(62) SDK: LXu_LOGENTRY, etc. defines
#define LXu_LOGENTRY "E83679B2-DB4D-4D90-B81B-5F786D212FB3" #define LXa_LOGENTRY "logentry"
Simple Messages
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.
(63) SDK: LogEntry::AddEntry
LXxMETHOD( LxResult, AddEntry) ( LXtObjectID self, LXtObjectID entry);
Info Blocks
Once an info block message has been created with AddMessageInfoBlock(), it needs to be populated with useful data.
First, we'll show an example of a populated block:
(64) Box Tool Info with subtitle and description text
Box (Squared) Low X: -1.0 m Y: -1.0 m Z: -1.0 m High X: 1.0 m Y: 1.0 m Z: 1.0 m Drag to change the size of the box. Right-click to make the box. Middle-click to scale the box around its center.
This sets a title that can appear at the top of the block, which in this case is "Box (Squared)".
(65) SDK: LogEntry::SetTitle
LXxMETHOD( LxResult, SetTitle) ( LXtObjectID self, const char *title );
This sets a description, which here is the three lines of text at the bottom of the block.
(66) SDK: LogEntry::SetDesc
LXxMETHOD( LxResult, SetDesc) ( LXtObjectID self, const char *desc );
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.
(67) SDK: LogEntry::SetValue
LXxMETHOD( LxResult, SetValue) ( LXtObjectID self, const char *name, unsigned int index, LXtObjectID value );
Name/Value Pairs
Name/Value pairs are both strings. Unlike info blocks, which have a fixed number of fields, there can be any number of pairs in an entry.
(68) Name/Value pair example
Left Click: Select Left Double-Click: Select Edge Loop Right Click: Menu Middle Click: Lasso Hold Ctrl, Shift and/or Alt for more options.
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.
(69) SDK: LogEntry::AddPair
LXxMETHOD( LxResult, AddPair) ( LXtObjectID self, const char *name, const char *value );
Properties
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:
(70) SDK: LXiLOGCLASS_MESSAGE, etc. defines
#define LXiLOGCLASS_MESSAGE 0 #define LXiLOGCLASS_BLOCK 1 #define LXiLOGCLASS_PAIRS 2
(71) SDK: LogEntry::Class
LXxMETHOD( LxResult, Class) ( LXtObjectID self, unsigned int *classType );
The type can be returned as an LxResult code.
(72) SDK: LogEntry::Type
LXxMETHOD( LxResult, Type) ( LXtObjectID self, LxResult *type );
The time at which the entry was logged can be read either as a C-style time_t or as a string via asctime().
(73) SDK: LogEntry::Time
LXxMETHOD( LxResult, Time) ( LXtObjectID self, time_t *time );
(74) SDK: LogEntry::TimeString
LXxMETHOD( LxResult, TimeString) ( LXtObjectID self, const char **string );
The list of child entries for MESSAGE class entries can be enumerated with these methods.
(75) SDK: LogEntry::ChildCount
LXxMETHOD( LxResult, ChildCount) ( LXtObjectID self, unsigned int *count );
(76) SDK: LogEntry::ChildByIndex
LXxMETHOD( LxResult, ChildByIndex) ( LXtObjectID self, unsigned int index, void **ppvObj );
A peek method is also available.
(77) SDK: LogEntry::PeekChildByIndex
LXxMETHOD( LXtObjectID, PeekChildByIndex) ( LXtObjectID self, unsigned int index );
Each root-level entry knows what subsystems it has been added to.
(78) SDK: LogEntry::SubSystemCount
LXxMETHOD( LxResult, SubSystemCount) ( LXtObjectID self, unsigned int *count );
(79) SDK: LogEntry::SubSystemByIndex
LXxMETHOD( LxResult, SubSystemByIndex) ( LXtObjectID self, unsigned int index, void **ppvObj );
Messages
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.
(80) SDK: LogEntry::Message
LXxMETHOD( LxResult, Message) ( LXtObjectID self, const char **message );
Info Blocks
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.
(81) SDK: LogEntry::Title
LXxMETHOD( LxResult, Title) ( LXtObjectID self, const char **title );
(82) SDK: LogEntry::Desc
LXxMETHOD( LxResult, Desc) ( LXtObjectID self, const char **desc );
This returns the info block definition.
(83) SDK: LogEntry::InfoBlock
LXxMETHOD( LxResult, InfoBlock) ( LXtObjectID self, 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.
(84) SDK: LogEntry::InfoBlockValue
LXxMETHOD( LxResult, InfoBlockValue) ( LXtObjectID self, const char *name, unsigned int index, void **ppvObj );
Name/Value Pairs
These mehtods return the number of pairs, and the name and value strings by index.
(85) SDK: LogEntry::PairCount
LXxMETHOD( LxResult, PairCount) ( LXtObjectID self, unsigned int *count );
(86) SDK: LogEntry::PairName
LXxMETHOD( LxResult, PairName) ( LXtObjectID self, unsigned int index, const char **name );
(87) SDK: LogEntry::PairValue
LXxMETHOD( LxResult, PairValue) ( LXtObjectID self, unsigned int index, const char **value );
Empty LogEntry Python user class.
(88) PY: empty LogEntry user class
pass
Threaded Support
We handle threading a slightly unique manner. By far the most common threaded operation is creating new log entries and adding them to a subsystem or another entry. There is little point in walking the log system hierarchy from a thread. Therefore, we only allow walking the hierarchy from the main thread, while any thread can create log entries and add them to subsystems or other entries as children. The only exception is the functions to walk the subsystem list, as a thread (such as an image I/O plug-in) will need to find the subsystem that its adding events to.
For simplicity, these new entries aren't actually added to their parents in the thread, but rather the add is defered until the main loop. The thread need not worry about this; it is handled in the background. Attempts to use other functions will fail.
Log Listener
The log listener can be used to listen for newly added log entries.
(89) SDK: LXu_LOGLISTENER define
#define LXu_LOGLISTENER "c5fd260b-cab7-4283-b876-2314144ae83a"
This is called when a new log subsystem (ILxLogID) has been added to the application.
(90) SDK: LogListener::SystemAdded
LXxMETHOD( void, SystemAdded) ( LXtObjectID self, LXtObjectID system);
Called when a new log entry is added to a subsystem. Note that a single log entry many belong to multiple subsystems.
(91) SDK: LogListener::EntryAdded
LXxMETHOD( void, EntryAdded) ( LXtObjectID self, LXtObjectID system, LXtObjectID entry);
Called when a new entry was added as a child of anohter log entry. This is only sent for root entries.
(92) SDK: LogListener::ChildEntryAdded
LXxMETHOD( void, ChildEntryAdded) ( LXtObjectID self, LXtObjectID entry, LXtObjectID parentEntry);
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.
(93) SDK: LogListener::EntryDropped
LXxMETHOD( void, EntryDropped) ( 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.
(94) SDK: LogListener::RollingEntryAdded, etc.
LXxMETHOD( void, RollingEntryAdded) ( LXtObjectID self, LXtObjectID system, LXtObjectID entry); LXxMETHOD( void, RollingChildEntryAdded) ( LXtObjectID self, LXtObjectID entry, LXtObjectID parentEntry); LXxMETHOD( void, RollingEntryDropped) ( LXtObjectID self, LXtObjectID system, LXtObjectID entry);
Empty LogListener Python user class.
(95) PY: empty LogListener user class
pass