1100 0000 1101 1110

0xc0.de/LibComponentLogging_

COMPONENT-BASED LOGGING FOR OBJECTIVE-C APPLICATIONS

Fork me on GitHub

LibComponentLogging is a small open source logging library for Objective-C applications on Mac OS X and the iPhone OS which provides conditional logging based on log levels and log components. Additionally, different logging strategies can be used, e.g. writing log messages to a file or sending them to the system log, while using the same logging interface.

LibComponentLogging is available under the terms of the MIT license.

LibComponentLogging is hosted on GitHub.

Found a bug? Missing a feature? Just drop a line to logging@0xc0.de, or create an issue in one of the repositories on GitHub.

Overview

LibComponentLogging is a small logging library for Objective-C applications which has the following characteristics:

In order to use the library in your application, just copy the files of the library core and the logger into your source directory, create a configuration file for your application's log components, add the library's implementation files to your project target, and compile them along with all other files of your project.

For step-by-step instructions, take a look at the installation section below.

Library Core

LibComponentLogging is split up into a library core accompanied by different loggers which implement certain logging strategies, e.g. one logger may write log messages to application-specific log files while another logger may send them to the system log, etc. This separation makes LibComponentLogging deployable for different application scenarios while using the same logging interface.

Core

The library core comprises the following files:

The main header lcl.h contains all definitions of the library core and serves as a main include file for all configuration files and other parts of the library. Therefore, an application should only include or import the lcl.h file, e.g. in its prefix header file.

Symbols for log levels and log components, which work with Xcode's code completion, are automatically provided by the main header file. All symbols, e.g. values or functions, which are relevant when using the logging interface in an application, are prefixed with 'lcl_'. Log levels share the common prefix 'lcl_v' and log components the prefix 'lcl_c'. Internal symbols, which are needed when working with meta data, when defining log components, or when writing a logger, are prefixed with '_lcl_'.

GitHub: Library Core | Repository | Recent Changes | Issues | Downloads

Logging Interface

The main interface for writing a message to the application's log is the macro lcl_log which creates a log message from the given arguments and sends it to the configured logger if logging is enabled for the given log component.

The syntax of lcl_log is similiar to NSLog's syntax:

lcl_log(<component>, <level>, @"<format>"[, <arg1>[, <arg2>[, ...]]]);

where

The use of a macro enables checking of the active log level before constructing the log message and before evaluating log message arguments. Therefore, if logging is disabled, the runtime-overhead of logging statements in an application is very low. Additionally, all logging code can be stripped from the application by re-defining the log macro to an empty effect, if required. Since version 1.1, the core's lcl.h file contains a definition of an empty log macro which is used if the preprocessor define _LCL_NO_LOGGING is defined.

At runtime, logging can be enabled/disabled for one or more log components by calling

lcl_configure_by_component(<component>, <level>);

or

lcl_configure_by_name(<name>, <level>);

where <component> is a log component or <name> is the full name of a log component which may include the wildcard suffix * in order to enable logging at the given level <level> for all log components with the same name prefix.

The library core provides the following log levels:

All log components of an application are defined in the file lcl_config_components.h by using the _lcl_component macro which has the following syntax:

_lcl_component(<identifier>, <header>, <name>)

where

Logging Examples

A lcl_config_components.h file which contains the following lines

_lcl_component(UIC1, "ui.c1", "User Interface/Component 1")
_lcl_component(UIC2, "ui.c2", "User Interface/Component 2")
_lcl_component(UIC3, "ui.c3", "User Interface/Component 3")

defines three log components 'Component 1', 'Component 2', and 'Component 3', which form the group 'User Interface'. Their log message headers are 'ui.c1', 'ui.c2', and 'ui.c3', and their identifiers are 'UIC1', 'UIC2', and 'UIC3'. Based on the defined log component identifiers, the library core automatically defines the code symbols lcl_cUIC1, lcl_cUIC2, and lcl_cUIC3, which must be used in calls to lcl_log, lcl_configure_by_component, etc.

Based on these log components, logging of critical messages, errors, warnings, and informational messages for all user interface components can be enabled by calling

lcl_configure_by_name("User Interface/*", lcl_vInfo);

Log messages can be created by the application by calling lcl_log, e.g.

lcl_log(lcl_cUIC2, lcl_vInfo, @"initialized");

lcl_log(lcl_cUIC1, lcl_vError, @"initialization failed, reason: %@", reason);

lcl_log(lcl_cUIC3, lcl_vTrace, @"button A pressed");

where the last log message for log component UIC3 will not be created and not written to the log, because the log level Trace is not active for the log component UIC3 in this example.

LogFile Logger

LogFile is a file logging class which writes log messages to an application-specific log file. The application's log file is opened automatically when the first log message needs to be written to the log file. If the log file reaches a configured maximum size, it gets rotated and all previous messages will be moved to a backup log file. The backup log file is kept until the next rotation.

LogFile

The logging class can be used as a logging back-end for LibComponentLogging, but it can also be used as a standalone logger without the Core files of LibComponentLogging, e.g. in combination with some simple DebugLog macros which do not know about log components. (since 1.1)

The LogFile logger uses the format

<date> <time> <pid>:<tid> <level> <component>:<file>:<line>:<func> <message>

where the file name, the line number and the function name are optional.

Example:

2009-02-01 12:38:32.796 4964:10b D component1:main.m:28:-[Class method] Text
2009-02-01 12:38:32.798 4964:10b D component2:main.m:32:-[Class method] Text
2009-02-01 12:38:32.799 4964:10b D component3:main.m:36:-[Class method] Text
GitHub: LogFile Logger | Repository | Recent Changes | Issues | Downloads

SystemLog Logger

SystemLog is a LibComponentLogging logger implementation which sends log messages to the Apple System Log facility (ASL).

SystemLog

With ASL, log messages are stored as structured messages in a data store. The syslog utility or the Console application can be used to retrieve messages from this data store.

Example:

syslog -F '$(Time) $(Sender)[$(PID):$(Thread)] $(Level0) $(Message) ($(Facility):$(File):$(Line))' -T utc -k Level0 -k Sender eq Example

retrieves all messages from the data store where the value associated with the 'Sender' key (the identifier of an application) is equal to 'Example' and where a value for the 'Level0' key exists. The key 'Level0' is used by SystemLog to store the log level in addition to a mapped ASL priority level ('Level' key). All retrieved messages will be printed by using the UTC time format and the display format specified via '-F':

2009.02.01 12:38:32 UTC Example[6717:10b] D Message 1 (example.f1:main.m:28)
2009.02.01 12:38:32 UTC Example[6717:10b] C Message 2 (example.f2:main.m:32)
2009.02.01 12:38:32 UTC Example[6717:10b] I Message 3 (example.f3:main.m:36)

The logging class can be used as a logging back-end for LibComponentLogging or as a standalone logger without the Core files of LibComponentLogging, e.g. wrapped by your own DebugLog macros. (since 1.1)

GitHub: SystemLog Logger | Repository | Recent Changes | Issues | Downloads

NSLog Logger

The NSLog logger implements a very simple logger which redirects logging to NSLog, but adds information about the log level, the log component, and the log statement's location (file name and line number).

The logger uses the following format

<NSLog prefix> <level> <component>:<file>:<line> <message>

where NSLog prefix is the header information written by NSLog. This header contains the current date and time, the application's name, the process id, and the thread id.

Example:

2009-02-01 12:38:32.796 Example[4964:10b] D component1:main.m:28 Message
2009-02-01 12:38:32.798 Example[4964:10b] D component2:main.m:32 Message
2009-02-01 12:38:32.799 Example[4964:10b] D component3:main.m:36 Message
GitHub: NSLog Logger | Repository | Recent Changes | Issues | Downloads

Installation

Download the files of the library Core and a logging back-end, e.g. the LogFile logger, from their repositories on GitHub:

Extract the files and copy the extracted files to your application's source directory.

Open Xcode and add all files of the library to your application's project. Xcode will automatically add the library's implementation files to your project's target.

Create a lcl_config_logger.h file and set up the logger, e.g. set the maximum file size and the name of the log file for the LogFile logger.

Create a lcl_config_extensions.h file and optionally add #import statements for logging extensions.

Create your application's lcl_config_components.h file.

Add a #import statement for lcl.h to your application files, e.g. to your application's prefix header file.

Define your log components in lcl_config_components.h.

Add lcl_log(...) log statements to your application.

GitHub Repositories

Library Core

Loggers

Extensions

Examples

Notes and Known Problems

If Xcode's code completion doesn't show your 'lcl_c'-prefixed log components, close Xcode, open a terminal, touch the lcl.* files in your application's source directory, and restart Xcode.

If your project is a Mac OS X framework, rename the Objective-C classes of the logger by adding your framework's unique name prefix, e.g. MyFramework, in order to avoid duplicate symbols in the global namespace. A convenient way to rename the classes is to add preprocessor defines like

#define LCLLogFile MyFrameworkLCLLogFile

as the first statements in the lcl_config_logger.h file.

Bugs and Feature Requests

Please send bugs, feedback, and feature requests to logging@0xc0.de, or create an issue in one of the repositories on GitHub.

Copyright and License

Copyright 2008-2010 Arne Harren <ah at 0xc0.de>.

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.

qlog - quick logging macros

JUNE 20, 2010 21:05

qlog is a set of quick logging macros for LibComponentLogging.

http://github.com/aharren/LibComponentLogging-qlog

qlog provides a short macro for every log level of LibComponentLogging, e.g. qlerror() for error messages and qltrace() for trace messages. Additionally, all logging macros take the current log component from a preprocessor define which can be (re)defined in your application at a file-level, section-based, or global scope.

To use qlog, simply add the qlog.h file to your project and define the preprocessor symbol ql_component at a global scope with your default log component, e.g.

#define ql_component lcl_cDefaultLogComponent

Then, logging statements can be added to your application by using the qlog macros instead of LibComponentLogging's lcl_log macros, e.g.

qlinfo(@"initialized");
qlerror(@"file '%@' does not exist", file);
qltrace();

If you want to use a specific log component for all logging statements in a file, you can simply redefine ql_component to match this log component, e.g. by adding a #undef #define sequence at the top of the file:

#undef ql_component
#define ql_component lcl_cFileLevelComponent

ah

LibComponentLogging SystemLog, Feature Build 1.1.1

APRIL 2, 2010 14:45

A new release of the LibComponentLogging SystemLog logger, which sends log messages to the Apple System Log facility (ASL), is available for download from the project's repository on GitHub:

http://github.com/aharren/LibComponentLogging-SystemLog

Build 1.1.1 adds the following features:

The SystemLog logger is compatible to LibComponentLogging Core 1.0 and 1.1, and can be used without LibComponentLogging Core.

ah

LibComponentLogging LogFile, Maintenance Build 1.1.2

FEBRUARY 21, 2010 23:07

Build 1.1.2 of LibComponentLogging's LogFile logger fixes the following bug:

The new build is available from the repository on GitHub:

http://github.com/aharren/LibComponentLogging-LogFile

ah

LibComponentLogging LogFile, Feature Build 1.1.1

FEBRUARY 10, 2010 20:57

The first stable build of the LibComponentLogging LogFile logger 1.1 release is available from the project's repository on GitHub:

http://github.com/aharren/LibComponentLogging-LogFile

Build 1.1.1 adds the following features and bug fixes:

The LogFile logger can be used in combination with LibComponentLogging Core 1.0 and 1.1.

ah

LibComponentLogging UserDefaults, Build 1.0.1

FEBRUARY 5, 2010 17:31

UserDefaults is a LibComponentLogging Core extension which stores/restores settings to/from the user defaults. Currently, the extension can store/restore active log level settings.

The UserDefaults extension is living in its own repository on GitHub:

http://github.com/aharren/LibComponentLogging-UserDefaults

The following code shows a simple usage pattern for the UserDefaults extension in your application's main.m file:

#include "lcl.h"
#include "LCLUserDefaults.h"

int main(int argc, char *argv[]) {
  // restore the log level settings from the standard user defaults
  [LCLUserDefaults restoreLogLevelSettingsFromStandardUserDefaults];

  // start your application
  ...
}

The UserDefaults extension uses the following format for storing log level settings in your application's domain:

"logging:<bundle identifier>:<log component name>:level" = <integer>

Examples:

"logging:com.yourcompany.YourApplication:Application/Component 1:level" = 5
"logging:com.yourcompany.YourApplication:Application/Component 2:level" = 3

You can simply change the log level settings from the command line by using the 'defaults' command, e.g.

defaults write <application> "logging:com.yourcompany.YourApplication:Application/Component 1:level" -int 2

ah

LibComponentLogging Core, Feature Build 1.1.1

FEBRUARY 3, 2010 22:05

Core

Build 1.1.1 of LibComponentLogging Core is available on GitHub. It adds the following features:

ah

LibComponentLogging LogFile, Example Xcode Project

JANUARY 27, 2010 21:45

Just pushed an example Xcode project to GitHub which bundles the library Core and the LogFile logger of LibComponentLogging with a small example application:

http://github.com/aharren/LibComponentLogging-LogFile-Example

The project contains the latest builds of LibComponentLogging Core (build 1.0.4) and the LogFile logger class (build 1.0.3).

ah

LibComponentLogging Core, Maintenance Build 1.0.4

JULY 25, 2009 18:27

Maintenance build 1.0.4 of LibComponentLogging Core fixes an issue with the main logging macro lcl_log in the Core part of the library which prevented the definition of custom logging macros on top of lcl_log.

With build 1.0.4, it is now possible to define simplified logging macros which draw the current log component from a file-level (or global) #define, e.g.

#define log_info(_format, ...) \
  lcl_log(FileLevelLogComponent, lcl_vInfo, _format, ##__VA_ARGS__);
#define FileLevelLogComponent \
  lcl_cUIC1

log_info(@"initialized");

ah

LibComponentLogging LogFile, Feature Build 1.0.3

JUNE 7, 2009 15:10

Feature build 1.0.3 of LibComponentLogging LogFile adds the ability to append to an existing log file instead of always creating a new log file on startup.

ah

LibComponentLogging Core, Maintenance Build 1.0.3

MAY 30, 2009 16:34

Maintenance build 1.0.3 of LibComponentLogging Core fixes some small issues in the Core part of the library:

ah

LibComponentLogging Core, Maintenance Build 1.0.2

APRIL 26, 2009 22:32

The maintenance build 1.0.2 of the Core part of LibComponentLogging adds a missing import for the Foundation framework to the lcl.h main header file.

Without this import, the compiler may complain about a bad definition of the type _lcl_level_t if lcl.h is imported without a preceding import of the Foundation framework, e.g. if lcl.h is imported as the first file in the prefix header file or if no prefix header is used.

ah

Logging to a File or to the System Log

FEBRUARY 21, 2009 12:22

Additional logger implementations are available for LibComponentLogging:

ah

Component-based Logging for Objective-C Applications

JANUARY 25, 2009 23:15

After working with Objective-C on Mac OS X and the iPhone OS for a while now, I've factored out some code for component-based logging for Objective-C applications into a small open source library named LibComponentLogging.

The library is designed ...

LibComponentLogging is split up into a Core part, which provides the main logging concepts like log levels and log components, and Loggers, which implement concrete logging strategies, e.g. writing the log messages into a file. This separation makes LibComponentLogging deployable for different application scenarios, e.g. an application may write its log message to a file while another application may send them to the system log.

ah