Linux Event Logging For Enterprise-Class Systems

Version 1.41  (not yet fully updated for evlog-1.5.0 release)

 December 6, 2002

 

NOTE:  For a listing of features that are not yet available, along with a list of planned enhancements to existing features, click here.

 

Team Members:

Larry Kessler  (lkessler@users.sourceforge.net)

James Keniston  (kenistoj@users.sourceforge.net)

Hien Nguyen (nguyhien@users.sourceforge.net)

   

1     Abstract. 3

2         Introduction.. 3

3         Goals.. 4

4         Compliance with proposed POSIX Standard 1003.25.. 5

5         Linux Event Logging Overview... 6

6         Linux Event Logging Detailed Description.. 7

6.1        Event Record Contents. 7

6.1.1        Fixed portion of Event Record. 7

6.1.2        Variable-length portion of Event Record. 8

6.1.2.1       POSIX_LOG_STRING.. 8

6.1.2.2       POSIX_LOG_BINARY. 8

6.1.2.2.1        Formatting Templates. 8

6.1.2.2.1.1        General Format of a Template. 8

6.1.2.2.1.1.1    Cpp Directives. 9

6.1.2.2.1.2        Imports and Typedefs. 9

6.1.2.2.1.2.1    Typedef Statements. 9

6.1.2.2.1.2.2     Import Statements. 9

6.1.2.2.1.3        Header Section. 10

6.1.2.2.1.3.1           Header of Record Template. 10

6.1.2.2.1.3.2           Header of Struct Template. 10

6.1.2.2.1.4        Attribute Sections. 10

6.1.2.2.1.4.1           Attribute Name. 11

6.1.2.2.1.4.2           Attribute Type. 11

6.1.2.2.1.4.3           Attribute Dimension or Bit-Field Width. 11

6.1.2.2.1.4.4           Const Attribute’s Value. 12

6.1.2.2.1.4.5           Attribute Format 12

6.1.2.2.1.4.6     More about Typedefs. 15

6.1.2.2.1.4.7    Alignment of Attributes in a Record or Struct 15

6.1.2.2.1.5        Template Formatting Specification. 16

6.1.2.2.1.5.1    Free Form.. 16

6.1.2.2.1.5.2    format string. 16

6.1.2.2.1.5.3    format wstring. 16

6.1.2.2.1.6        Sample Templates. 16

6.1.2.2.1.7        More on Importing Templates. 18

6.1.2.2.2         Using formatting templates with POSIX_LOG_STRING and POSIX_LOG_NODATA   18

6.1.2.2.3        Advantages and Disadvantages. 19

6.2      Event Logging and Retrieval 19

6.2.1        Facility Registry. 19

6.2.1.1       Restricted Logging. 21

6.2.2        evlogd Daemon  and Event Buffering. 21

6.2.2.1       Screening of Events. 22

6.2.2.2       Discarding duplicate events. 23

6.2.3        API Functions. 24

6.2.3.1       Writing Event Records. 24

6.2.3.1.1        Writing Events from User Space. 24

6.2.3.1.2        Writing Events from Kernel Space. 26

6.2.3.2       Formatting Event Records. 29

6.2.3.3       Formatting Templates. 32

6.2.3.3.1        The Template Repository. 32

6.2.3.3.2   Notes on template Use in Multithreaded Applications. 33

6.2.3.3.3        Compiling Templates. 33

6.2.3.3.4        Template Application. 34

6.2.3.4         Registering Facilities. 41

6.2.3.4.1        Registering Facilities from User space. 41

6.2.3.4.2        Registering Facilities from Kernel space. 42

6.2.4        User Commands. 43

6.2.4.1        evlconfig - Configure logging daemon. 43

6.2.4.2       evlfacility - Manage Facility Registry. 45

6.2.4.3        evlsend -  Event generation command. 48

6.2.4.4         evlview - View log events. 49

6.2.4.5       evltc - Compile formatting templates. 54

6.3        Filtering of Event Records. 57

6.4          Event Notification. 58

6.4.1        Overview.. 58

6.4.2        Detailed Design. 59

6.4.2.1       evlnotifyd  Server Design. 59

6.4.2.1.1        Processing a New Notification Request 60

6.4.2.2        Client Design. 61

6.4.2.2.1        posix_log_notify_add() 61

6.4.2.3       Client-Server Conversations. 61

6.4.2.3.1        Types of Messages. 61

6.4.2.3.2        Creating a Notification Request 61

6.4.2.3.3        Getting the Status of a Notification Request 61

6.4.2.3.4        Removing a Notification Request 62

6.4.2.4       evlactiond Client 62

6.4.2.4.1        Registering for event notification. 62

6.4.2.4.2        Processing an event notification. 62

6.4.2.5       Threads-Based Notification. 63

6.4.3        API Functions. 63

6.4.4        User Commands. 63

6.4.4.1       evlnotify - Event Notification. 63

6.5      Log Management 66

6.5.1      User Commands. 68

6.5.1.1       evlogmgr - Event Log Manager. 68

6.6      Query and Filter Expression Syntax Rules. 71

6.6.1 Extensions to the POSIX Standard. 74

6.7      Modifications to the Linux Kernel 74

6.7.1      Enhanced printk. 74

6.8      Modifications to syslog. 75

7         Appendices.. 76

7.1      Appendix A  POSIX 1003.25 **DRAFT**. 76

7.2      Appendix B Overview of Syslog 1.3 (for Linux) 76

Syslogd Options. 76

Remote Logging of syslog messages. 76

syslog.conf 77

severity codes. 77

Additional syslog options. 78

klogd. 78

logger command. 79

Log File Management / logrotate command. 79

Associated Files. 80

7.3      Appendix C Issues and New Requirements. 81

7.4      Appendix D siginfo.h header file. 81

7.5      Appendix E   Date and Time Formats. 84

7.6      Appendix F   Facility Names and Facility Code creation. 85

8         Revision History.. 86

 

 

 

 

1     Abstract

This document describes an Enterprise-class Event Logging facility for Linux.   Refer to Appendix C Issues and New Requirements for items that are not currently addressed in the body of this document.

2         Introduction

For the purpose of problem tracking and problem determination, events and informational messages from kernel subsystems and system applications are logged for later analysis.

In Linux, the most commonly used logging facilities are printk/klog (for logging kernel events) and syslog (for logging non-kernel events), which is referred to collectively as sysklogd.   See Appendix B Overview of Syslog 1.3 (for Linux).  Although quite suitable for single-processor desktop or small server applications, for multi-processor medium-to-large servers, commonly found in medium-to-large enterprises, sysklog has several shortcomings, which include:

              Events are recorded as text only, and some pertinent information (for example, facility and severity) is not recorded.  Also, events can be recorded in multiple destinations, which makes effective post-processing of messages/events difficult.

              Limited user interface is available to extract, filter, and view only events of interest. 

              A limited set of event providers (facilities) are supported, with only 8 available for the implementation to define (LOCAL0-7).

              Limited Event "notification" capabilities.

              Limited ability to manage and limit syslog generated log file sizes and the age of the events (logrotate, a separate RPM, does provide archiving capability based on age or size of the entire log file, but it does not allow selective removal of events from the log files based on user or application specified criteria). 

 

 

3         Goals

Given sysklogd's limitations, and the need to provide additional capabilities for large, multi-processor, Enterprise-class systems, the goals are:

 

 


4         Compliance with proposed POSIX Standard 1003.25

 

Linux Event Logging conforms to proposed POSIX Standard 1003.25, System API - Services for Reliable, Available, and Serviceable Systems (SRASS).  As of March 2002, this standard has not been adopted, and the descriptions provided within are subject to change, accordingly. 

Appendix A  POSIX 1003.25 **DRAFT** contains a link to the most recent draft of this standard.   The information in Appendix A will not be repeated in the body of this document, except when additional explanation is needed.  It is recommended that you read and become familiar with the draft POSIX standard before reading the remainder of this document.  Through active participation in the IEEE Working Group, the authors of this document will keep this document consistent with latest draft of the POSIX Standard.

In summary, the requirements and functionality specified in the latest draft of the standard:

1.        A single system-wide log that is always available to accept event records.

2.        All event records consist of a fixed structure representing attributes of the event record and a variable-length data buffer containing the event data (text or binary).

3.        API functions exist for applications to:

·         write to the log

·         open the log (required for reading, but not required for writing to the log)

·         seek to record(s) that match the selection criteria. 

·         Register for event notification, where a real-time signal is generated and a sigval object is passed, when an event record is written to the log which contains values that match the specified selection criteria. 

 

It should be noted that there is a deviation from the "single system-wide log" requirement specified by the POSIX standard, which is provided in order to more closely match the current behavior of sysklogd with respect to logging AUTHPRIV messages into a separate "private" log file with restricted read access.  See Facility Registry for a detailed explanation.

5         Linux Event Logging Overview

 

There are two primary interfaces to Event Logging as defined by the direction of information flow. They are the Provider Interface and the Consumer Interface.   A secondary interface is provided for Log Management.

The following diagram illustrates the flow of information.


http://evlog.sourceforge.net/evl1.gif

 

The Provider Interface is used by software to report events.  Providers may include commands executed from the command line or shell script.  With every event, a base set of information must be provided to make the event data useful for analysis and acceptable for logging.

The Event Logging system collects additional information, such as time of the event, combines it with the provider-supplied data, and creates an event log entry.  The Event Logging System also:

·         Optionally takes printk() and syslog()/vsyslog() messages, and logs them as POSIX-compliant event records.

·         Optionally, and based upon specified thresholds, suppresses logging of duplicate events being logged in rapid succession, to minimize system performance degradation.

·         Optionally, and based upon specified criteria, screens events that are written to the log.  For example, messages for debugging purposes may not be of interest to a System Administrator. 

·         Filters events that are read from the log, based on specified criteria.

·         Notifies registered Consumers, when events match Consumer-specified criteria.

·         Provides a method for configuring the event buffer size

 

The Consumer Interface:

 

·         Retrieves selected event data (based on Consumer specified selection criteria) from the log.

 

 

·         Registers for notification (based on Consumer specified criteria) when events matching the criteria are written to the log.  

 

The Consumer-interface users typically include system end users (mostly system administrators and operators) and service/support groups.

 

Log Management:

·         Provides methods for:

o        Managing the size of the event log.

o        Specifying criteria for automatically removing events from the log that are no longer of interest, truncating the log, and reclaiming the space.

 


6         Linux Event Logging Detailed Description

6.1        Event Record Contents

An Event Record consists of a fixed-length, predefined structure, and a variable-length portion, up to POSIX_LOG_ENTRY_MAXLEN long, which contains event data attributes that are passed by the provider of the event record. 

6.1.1        Fixed portion of Event Record

See Appendix A for contents of the fixed-portion of the event record.   Additional content has been defined as follows:

·         The following log_event_types  are reserved:

EVL_PRINTK_MESSAGE  (0x2) - indicates that event was originally written with the printk() function.  All messages written with printk() will have this event type unless the event logging feature that includes caller location information (source file, function, line number)  is enabled, in which case the event type will be a checksum derived from source file name, function name, and printk format string.  The log_facility will always be LOG_KERN for this event type.

EVL_SYSLOG_MESSAGE  (0x1) - indicates that event was originally written with the syslog() or vsyslog() function.    The log_facility will be passed by the caller of syslog().

EVL_BUFFER_OVERRUN (0x6) - indicates that one or more event records have been discarded due to an overrun of the kernel event buffer, or temporary event buffer allocated by the evlogd daemon.  The log_facility will always be LOG_LOGMGMT for this event type.  See Event Buffer and evlogd Daemon for more information.

EVL_DUPS_DISCARDED (0x7) - indicates that one or more duplicate event records have been discarded.  The log_facility will always be LOG_LOGMGMT for this event type.  See Discarding duplicate events for more information.

EVLOG_REGISTER_FAC (40) - indicates that the event is a special event generated when evl_register_facility() is called in the kernel.  See Registering Facilities from Kernel space for details.

·         The following log_flags bits have been reserved for use by event logging:

                POSIX_LOG_TRUNCATE (0x1) - Defined in the POSIX standard.

EVL_KERNEL_EVENT (0x2) - Indicates that event was logged from within the kernel.   If caller of log write functions in user-space (evl_log_write, posix_log_write, etc.) sets this flag to 1, ECANCELED is returned and the event is not logged.  This is intended to prevent an application or user from erroneously indicating that the event was logged in the kernel, when in fact it was logged in user-space.

EVL_INITIAL_BOOT_EVENT (0x4) - This bit indicates that the event was logged before a valid  time value was available in the kernel.  When this bit is set the evlogd daemon will overwrite the log_time field in the event record with the system startup time (determined by subtracting uptime from current time), and thus provides a reasonable approximation for log_time.

EVL_KERNTIME_LOCAL (0x8) - This bit indicates that the log_time value in the event record (created in the kernel) is set to local time, and needs to be adjusted to GMT by the evlogd daemon.  evlogd will reset this bit after the time is adjusted.

EVL_INTERRUPT (0x10) - This bit indicates that the event was logged from interrupt context. 

EVL_PRINTK_MESSAGE  (0x20) - indicates that event was originally written with the printk() function.  

Reserved for future event logging use:  0x40, 0x80.

 

6.1.2        Variable-length portion of Event Record

The 2  variable-length data formats defined in the POSIX standard are supported, as indicated by the log_format value:

·         POSIX_LOG_STRING - A NULL-terminated string.

·         POSIX_LOG_BINARY - Binary data, requiring additional information to interpret and format.

POSIX_LOG_NODATA is also a valid log_format, and indicates that there is no variable-length data associated with the event.  

 

6.1.2.1       POSIX_LOG_STRING

The POSIX standard requires that compliant implementations support variable-length event data consisting of a NULL-terminated character string.

 

6.1.2.2       POSIX_LOG_BINARY

Binary data can be described as a contiguous string of bytes representing one or more attributes in the optional portion of an event record.  The information needed for parsing and formatting the optional attributes contained within this binary data is provided by formatting templates.

 

6.1.2.2.1        Formatting Templates

NOTE:  Although formatting templates are primarily intended for use with log_format of POSIX_LOG_BINARY, they can also be used with other log_formats.  See 6.1.2.2.2         Using formatting templates with POSIX_LOG_STRING and POSIX_LOG_NODATA for details.

There are 5 sections in a template:

 

  1. Imports and Typedefs
  2. Header
  3. Const attributes (optional)
  4. Record attributes
  5. Template formatting specification

 

These sections are described in detail below.

6.1.2.2.1.1        General Format of a Template

The imports/typedefs, header, and attribute sections of a template are made up of statements.  In general, statement syntax follows the conventions of the C language.  In particular, the following language elements follow C syntax:

·         comments

·         identifiers

·         string and wide-string literals, including automatic concatenation of adjacent string literals or adjacent wide-string literals

·         integer, char, wide-char, and floating-point constants

·         white space

In the header and attribute sections, statements are terminated with semicolons (;).  A single line can contain multiple statements, and a single statement can span multiple lines.

The final section of the template, the template formatting specification, may be in the form of a statement, or it may be free-form text.  Its format is defined later in this discussion.

The special statement END (upper case, no semicolon, no white space, no comments, on a line by itself) is used to separate multiple templates in the same source file.  The final template in a file need not contain an END statement.

6.1.2.2.1.1.1    Cpp Directives

The evltc template compiler has the option of passing your template source code through the C preprocessor, cpp, before compiling it.  Therefore, your template source code can include C-preprocessor directives such as #include, #define, and #ifdef, with appropriate results.

6.1.2.2.1.2        Imports and Typedefs

The imports/typedefs section contains zero or more import statements and zero or more typedef statements.  Within this section, import and typedef statements can appear intermixed in any order.  The imports and typedefs remain in effect through the end of the template source file.

6.1.2.2.1.2.1    Typedef Statements

A typedef statement in a template is analogous to a typedef statement in the C language.  Each typedef statement has the form

        typedef type_spec  name  dimension_spec  format_spec ;

where type_spec, name, dimension_spec, and format_spec are defined as for attribute statements.  (See “Attribute Sections” later in this discussion.)  The specified name can be used as a type_spec in subsequent attribute statements.  Each such attribute assumes the typedef’s type, its dimension (if any), and possibly its format (if any).  For a further explanation of typedefs, see the “More on Typedefs” section under “Attribute Sections.”

6.1.2.2.1.2.2     Import Statements

Each import statement has the form

      import struct_path ;

 

A struct_path is a sequence of one or more identifiers delimited by periods.  This sequence identifies a struct template (see next section) that is referenced later in this template file.  For example, the statement

      import gui.graphics.point;

would typically import the struct template from the file /var/evlog/templates/gui/graphics/point.to.  The importing template can then declare attributes of type “struct point” or “struct gui.graphics.point”.

 

The final component of a struct_path can be an asterisk (*), specifying that all struct templates from the indicated directory should be imported.  For example, the statement

      import gui.graphics.*;

would typically import the templates from all the .to files in the /var/evlog/templates/gui/graphics directory.

 

Importing a struct template brings a binary representation of that template into memory, much as if that template had been previously defined in the current template source file.  Importing of templates is further discussed in the section “More on Importing Templates,” later in this discussion of formatting templates.

6.1.2.2.1.3        Header Section

There are two types of templates that are used to describe event records:

 

Record and struct templates differ primarily in the content of their header sections.

 

6.1.2.2.1.3.1           Header of Record Template

The header of a record template contains 3 statements that must be specified in the following order.  (The description statement is optional.)

facility facility_id ;

event_type event_id ;

description description ;

 

 

The facility_id identifies the facility to which this template applies; it corresponds to the log_facility member in the fixed portion of an event record.  The facility_id is either an integer constant or a string literal from the facility registry (see Facility Registry) -- e.g.,

 

facility 128;

facility "MAIL";

facility "Bob’s Volume Manager";

 

The event_id is an integer constant that corresponds to an event record's log_event_type member.  Together, the facility and event-type match the template to a particular type of event record.

 

An event_type statement may also be of the form

      event_type default;

This indicates that this template will be used by default for any event type, in the indicated facility, that does not have its own template.

 

The description is a string literal that contains a human-readable title for the template. 

6.1.2.2.1.3.2           Header of Struct Template

The header of a struct template contains a struct statement and an optional description statement, in that order.  The description statement is as described above.  The format of a struct statement is

[const] struct struct_name ;

where struct_name is an identifier that uniquely identifies this struct.

 

A struct template that is declared const must have a const-attributes section and no record-attributes section.  Such a template is used solely to define const values that may be referenced in other templates.  A non-const struct template must have at least a record-attributes section.

6.1.2.2.1.4        Attribute Sections

A template may have a record-attributes section and/or a const-attributes section.  The const-attributes section defines attributes with fixed values that are provided by the template, and are not included in the event record.  The record-attributes section defines attributes in the order that they appear in the optional part of the event record.

Each section consists of three parts:

1.        the start-attributes clause.  For the const-attributes section, this is “const {“.  For the record-attributes section, this is “[aligned] attributes {“.  The optional “aligned” keyword specifies that the attributes are aligned as if they were members of a C struct (and therefore may contain padding after some values).  The “aligned” option is discussed further under “Alignment of Attributes in a Record or Struct.”

2.        one or more attribute statements, each of which resembles a C-language data declaration

3.        the end-attributes clause: “}

In the record-attributes section, an attribute statement specifies the name, type, and formatting specification of an attribute, and (if it is an array or bit-field) its dimension.  The format of the statement is

 type_spec  name  dimension_spec  format_spec ;

 

In the const-attributes section, each attribute statement also specifies a value for the attribute (unless the attribute is a const struct, which carries its own predefined values):

 type_spec  name dimension_spec = value_spec  format_spec ;

 

The record-attributes section cannot include attributes that are const structs.

6.1.2.2.1.4.1           Attribute Name

The attribute’s name is a valid C-language identifier that distinguishes this attribute from other attributes defined in this template. (However, this name may be the same as the name of one or more attributes defined in struct templates referenced by this template.)  The following attribute names are reserved, as explained in POSIX 1003.25: recid, size, format, event_type, facility, severity, uid, gid, pid, pgrp, time, flags, thread, processor, data.  The following words are also reserved: aligned, attributes, const, default, description, import, signed, struct, typedef, unsigned, and all the type names listed in the “Table of Optional Attribute Data Types and Format Specifiers” later in this section.

 

6.1.2.2.1.4.2           Attribute Type

The attribute’s type_spec can take one of the following forms:

·         one of the type names listed in the table later in this section (e.g., “ushort”, “ldouble”);

·         the C-language equivalent of one of those type names (e.g., “unsigned short”, “long double”);

·         the name of a previously defined typedef (see “More about Typedefs” later in this section); or

·         the construct “struct struct_name” where struct_name is the name of a struct template that was previously defined or imported in the current template source file.  If the specified struct template was not previously defined or imported in the current file, but a file named struct_name.to exists in the same directory as the current file, that struct template will be imported automatically.

6.1.2.2.1.4.3           Attribute Dimension or Bit-Field Width

The attribute’s dimension_spec is omitted if the attribute is not an array or bit-field.  If the attribute is an array, the dimension_spec is one of the following constructs, enclosed in square brackets [ ]:

 

A const attribute cannot have a dimension of [_R_] or [*].

Multi-dimensional attributes per se are not supported.  However, you could obtain the effect of a two-dimensional array as follows: A struct may contain an array as its only attribute, and another template may declare an array of such structs.

Bit-Fields.  If the attribute is a bit-field, the dimension_spec has the format

: width

where width is the attribute’s size in bits, an integer constant.  Bit-field attributes have the same semantics as C-language bit-fields, with the following exception:

·         The width must be a decimal, hexadecimal, or octal integer constant.

Bit-field storage and alignment conventions match those of gcc on the system that wrote the event log.  The size of a bit-field cannot exceed the size of a long long.  Unnamed bit-fields are permitted.  In particular, the “int :0” construct (which in C means, “skip to the beginning of the next storage unit”) is supported.

A const attribute cannot be a bit-field.

6.1.2.2.1.4.4           Const Attribute’s Value

A const attribute’s value_spec is a constant (string literal, or integer, floating-point, or character constant) that specifies the attribute’s value.  For aggregate attributes (records and arrays), C-style aggregate initializers are used – for example:

const {

      struct point origin = {0,0};

      int daysPerMonth[12] = {31, 28, 31, 30, 31, 30,

31, 31, 30, 31, 30, 31} “(%d )”;

      struct xpg4Msg probableCauses[] = {

            {2, 1, “Operator fell asleep”},

            {2, 2, “Backhoe”}

      } “(Probable cause[%I] = %Z\n)”;

}

 

Formatting of arrays and structs is discussed in the next subsection.

Due to automatic concatenation of string literals, the following attribute statement, though legal, will probably not produce the intended effect:

string helpMsg = “Help!” “%-20s”;

 

To resolve this problem, even a scalar attribute’s value_spec can be enclosed in curly braces – e.g.,

string helpMsg = { “Help!” } “%-20s”;

6.1.2.2.1.4.5           Attribute Format

The attribute’s format_spec is a string literal that specifies how the attribute is to be formatted.

 

If the attribute is a scalar (simple) attribute – not an array or struct – the format_spec must be a valid printf format specification for a single value of that type, beginning with a “%” and ending with one of the format specifiers from the table below.  The standard printf flags (‘-‘, ‘+’, space, ‘#’, and ‘0’) and field-width and precision specifiers are also permitted.

 

If the format_spec is omitted, the format specifier defaults to the one shown for that data type in the table.  For example, the default format_spec for ints, shorts, and chars is “%d”.

 

The special format specifiers %t, %b, and %v are also supported, as described later in this section.

Table of Optional Attribute Data Types and Format Specifiers used with formatting templates.

Type Names

Applicable printf Format Specifiers

Default Specifier

short

d, i, o, x, X, u without flag h or l

d

ushort

d , i, o, x, X, u without flag h or l

u

int

d , i, o, x, X, u without flag h or l

d

uint

d , i, o, x, X, u without flag h or l

u

long

d , i, o, x, X, u with flag l

ld

ulong

d , i, o, x, X, u with flag l

lu

longlong

d , i, o, x, X, u with flag L

lld

ulonglong

d , i, o, x, X, u with flag L

llu

address

d, i, o, x, X, u with flag l, p

p

float

f, e, E, g, G

f

double

f, e, E, g, G

f

ldouble

flag L with f, e, E, g, G

Lf

schar

c, C, d , i, o, x, X, u without flag h or l

d

uchar

c, C, u , i, o, x, X, u without flag h or l

u

char

Same as either schar (signed char) or uchar,

depending on whether char is signed or unsigned

on the system where evltc was built.

d or u

string

s

s

wchar

C, flag l with c

lc

wstring

S, flag l with s

ls

 

Dump Format.  The format_spec can be %t for any attribute.  %t indicates that the data should be displayed in dump format: hexadecimal, with the ASCII equivalent also displayed.  For example, given an attribute definition of “uchar x[32]”, a formatting specifier of %t might produce the following:

 

00000000 61 62 63 64 65 66 67 68  61 62 63 64 65 66 67 68 | abcdefgh abcdefgh

00000010 3F 3F 3F 3F 4A 3F 3F 3F  3F 3F 3F 3F 4A 3F 3F 3F | ????J??? ????J???

 

Bitmaps.  For integer types, the %b format specifier can be used.  %b specifies that the attribute should be formatted as a bitmap.  A %b specifier has the following format:

 

"%b/bit_pattern1/string1/bit_pattern2/string2/.../bit_patternN/stringN/"

 

Each bit pattern is either a hexadecimal number beginning with 0x or 0X or x or X, or a binary pattern beginning with 0b or 0B or b or B.  For every bit pattern that matches the attribute’s value, the corresponding string is included in the formatted representation of the value.

 

In the examples shown in this section, the strings and bit patterns are delimited by slashes (/), but any punctuation character may be used as a delimiter.  In a %b or %v format specifier, the delimiter is the character immediately following the %b or %v.   The delimiter character cannot appear in any of the strings.

 

A hexadecimal bit pattern matches the attribute’s value if all the 1s in the hex value are also 1s in the attribute’s value – i.e., (attribute_value & hex_pattern) == hex_pattern.  For example, when the format specifier

"%b/0x1/HUMAN/0x2/ADULT/0x4/FEMALE/"

is applied to the value 5, the result is

0x5(HUMAN|FEMALE)

If it is applied to the value 8, the result is

0x8

 

A binary pattern is a sequence of 0s, 1s, and Xs (upper or lower case), each representing a bit.  All X bits, and all bits not explicitly specified, are treated as don’t-care bits.  0 and 1 bits must match the attribute’s value.  For example, the previous sample specification could be expressed as

"%b/0b1/HUMAN/0b1x/ADULT/0b1xx/FEMALE/"

To give non-humans, juveniles, and males (the “zero” bits) explicit recognition, we could expand the specification to

"%b/0b1/HUMAN/0b1x/ADULT/0b1xx/FEMALE/"

"0b0/INHUMAN/0b0x/JUVENILE/0b0xx/MALE/"

(Note that the two adjacent strings are automatically concatenated.)  Applied to the value 5, this specifier would produce

0x5(HUMAN|FEMALE|JUVENILE)

 

Once a pattern is matched, any subsequent patterns associated with those bits are ignored.  For example, If the specification

"%b/0x7/WOMAN/0x1/HUMAN/0x2/ADULT/0x4/FEMALE/"

is applied to the value 7, the result is

0x7(WOMAN)

not

0x7(WOMAN|HUMAN|ADULT|FEMALE)

 

Named Values.  Like %b, the %v format specifier is restricted to integer types, and specifies a set of value/string pairs.  When a value in the %v list exactly matches the attribute’s value, the corresponding string is substituted.  If there is no match, the attribute’s value in decimal is substituted.  For example, when the format specifier

"%v/1/Sun/2/Mon/3/Tue/4/Wed/5/Thu/6/Fri/7/Sat/"

is applied to the value 6, the result is “Fri”.  When it is applied to the value 8, the result is “8”.

 

Struct Attributes.  If the attribute is a struct, the format_spec must be omitted, since the format is specified in the struct’s template.  The special %Z specifier is used when formatting arrays of structs, as described under “Array Attributes.”

 

Array Attributes.  If the attribute is an array, the format_spec (if any) may be followed by the construct

      delimiter=string

where string is a string literal.  This delimiter string is inserted between the elements of the formatted array.  The default delimiter is a single space.

 

If the format_spec is omitted, the array's elements will be formatted using the default format for that type (or %Z, for an array of structs).

 

If specified, the format_spec must be one of the following constructs:

int   widgets[5] "%#x";

might yield the following formatted output:

0x5 0xa 0xc 0x43 0x3

 

Within the format_spec, %I and %Z have special interpretations.  %I is replaced by the index (in decimal) of the current array element.  For example, the attribute statement

int   widgets[5] "w[%I]=%2d" delimiter="\n";

might yield the following formatted output:

w[0]= 5

w[1]=10

w[2]=12

w[3]=67

w[4]= 3

 

%Z is used with arrays of structs, and stands for a single element of the array, formatted according to the struct’s template.  For example, the attribute statement

struct point endPoints[2] "endPoint[%I] = %Z" delimiter="\n";

                might yield the following output:

endPoint[0] = (10,15)

endPoint[1] = (-25,15)

 

int   widgets[5] "(%d, )";

might yield the following formatted output:

5, 10, 12, 67, 3,

 

6.1.2.2.1.4.6     More about Typedefs

The semantics of the components of a typedef statement are largely the same as those of an attribute statement.  A typespec defines a type, and may also define a dimension and/or format.  When a typedef’s name is given as an attribute’s type_spec, the attribute is defined as follows:

·         The typedef’s type is assigned to the attribute.

·         If the typedef defines a dimension, that will be assigned to the attribute; otherwise, the attribute’s dimension (if specified) will be used.  It is illegal for both the typedef and the attribute to explicitly specify dimensions.

·         If the attribute statement does not explicitly specify a format, the typedef’s format (if any) will be assigned to the attribute.

A typedef is not associated with any particular template.  Therefore, its dimension cannot be an attribute name.  However, it can be [_R_].

A typedef with a dimension of [ ] -- for example,

      typedef int int_array_t[] “(%d )”;

-- is legal.  However, only const attributes can be of this type (since the size of the array is determined from the initializer list).

A typedef cannot define a bit-field.  A typedef cannot be initialized with a value.

A typedef name cannot be a reserved word.  However, the same (legal) name can be used independently for a typedef, struct, and/or attribute.

The form

      typedef struct s { ... } s_t;

is allowed in C but not in a template.  The equivalent code for a template is:

      struct s; [aligned] attributes { ... } format string “...”

      END

      typedef struct s s_t;

6.1.2.2.1.4.7    Alignment of Attributes in a Record or Struct

The “aligned” keyword in a record-attributes clause specifies that, in the event record, the attributes’ values will be aligned as if they were members of a C struct.  As a result, the record is expected to contain padding between values (and possibly after the last value) to achieve alignment.

 

For example, a struct defined as follows --

                attributes { char c; int i; }

-- is expected to occupy 5 bytes on a 32-bit system: 1 for c and 4 for i.  The record might be written as follows:

      evl_log_write(facility, event_type, severity, flags,

            "char", c, "int", i);

 

By contrast, a struct defined as follows --

                aligned attributes { char c; int i; }

-- is expected to occupy 8 bytes on a 32-bit system: 1 for c, 3 for alignment, and 4 for i.  The record might be written as follows:

                struct s { char c; int i; } svar;

...

posix_log_write(facility, event_type, severity, &svar,

sizeof(svar), POSIX_LOG_BINARY, flags);

 

In a record or struct with aligned attributes, no attribute can have a size that is unknown at compile time.  Such attributes include strings, wstrings, variable-dimension arrays, and unaligned structs.

6.1.2.2.1.5        Template Formatting Specification

 

The last section of the template defines how the record’s formatted attributes are to be presented.  This section must appear immediately after the final attribute section.  This section can take three forms:

·         free form

·         format string string_literal

·         format wstring wide_string_literal

6.1.2.2.1.5.1    Free Form

A free-form formatting specification begins with the keyword “format” on a line by itself.    Everything that follows the format statement, until the end of the template, is interpreted as the format string.

The formatted representation of a template is a copy of this format string, with the appropriate formatted attribute value substituted wherever an %attribute_name% construct appears.   attribute_name can be a simple name (e.g., “employee”) or a reference to a struct member (e.g., “employee.addr.city”).

 

The %attribute_name% construct may include an embedded formatting specification -- e.g. "%lun:x% -- that overrides the format that would otherwise be used.  Any newline (line break) in the format string also appears in the formatted output, unless it is immediately preceded by a \.  Newlines, tabs, and other special characters can also be encoded using standard C escapes (\n, \t, etc.).

 

For an event-record template, a newline is automatically appended to the formatted representation, so that the formatted output of an event-record template always takes up at least one complete line.  For a struct template, any terminating newline must be explicitly specified – as a trailing blank line, as a \n escape, or as the last character of a formatted array attribute.

The C preprocessor does not always preserve white space intact.  So if you are going to run your template source file through the C preprocessor, you may want to use the “format string” or “format wstring” form instead.

6.1.2.2.1.5.2    format string

This form consists of the words “format string”, followed by one or more string literals, which are automatically concatenated into the format string.  The words “format” and “string” must be separated by at least one white-space character (but no newlines).

6.1.2.2.1.5.3    format wstring

This form consists of the words “format wstring”, followed by one or more wide-string literals, which are automatically concatenated.

6.1.2.2.1.6        Sample Templates

Here is a simple struct template:

struct point;

attributes {

      int   x;    /* Format defaults to %d */

      int   y;

}

format string "(%x%,%y%)"