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%)"

 

Here is a simple template that uses the “point” struct template:

facility "Jan's Graphics Editor";

event_type 456;

description "Circle has wrong color";

attributes {

      int               color       "%#6x";

      struct point      center;

      int               radius;

}

format

Circle with center %center% and radius %radius% has wrong color.

Color (RGB) = %color%.

 

This template might yield the following output:

Circle with center (40,55) and radius 20 has wrong color.

Color (RGB) = 0x00ff7f.

 

Here's a more complicated example:

/*****************************************************************/

/* HEADER SECTION */

facility "LOCAL1";

event_type 0x3115;

 

/* CONST-ATTRIBUTES SECTION */

const {

      string      repair_action = "Replace SCSI adapter";

}

 

/* RECORD-ATTRIBUTES SECTION */

attributes {

      char        unit_ser_no[8]    "(%c)";

      ushort      lun               "%u";

      char        sense_bytes[12]   "%t";

/* For the next attribute, the various sections of the format_spec are

 * automatically concatenated into a single string.

 */

      uchar       recovery_stat     "%b/0x40/INTERFACE_WAS_RESET/"

                                    "0x20/RECOVERY_ACTION_STARTED/"

                                    "0x10/RECOVERY_ACTION_FAILED/";

/* The final attribute specification says to display the rest of the

 * bytes in dump format.

 */

      char        extra_data[_R_]   "%t";

}

 

/* FORMATTING SECTION */

format

SCSI interface error: Adapter Serial Number/LUN = %unit_ser_no%/\

%lun%

 

\tRecovery Status: %recovery_stat%

\tSense Bytes:

%sense_bytes%

        

\tRecommended repair action:

\t\t%repair_action%\n\n

 

%extra_data%

/*****************************************************************/

 

This template might yield the following output:

SCSI interface error: Adapter Serial Number/LUN = XSCSI178/3

 

Recovery Status: 0x50(INTERFACE_WAS_RESET|RECOVERY_ACTION_FAILED)

Sense Bytes:

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

        

Recommended repair action:

Replace SCSI adapter

 

 

00000000 26 B3 B3 25 AB BC CD                              | &..%...

 

6.1.2.2.1.7        More on Importing Templates

The algorithm for finding the template specified in an import statement is as follows:

  1. The struct_path from the import statement is converted into a relative pathname by replacing all periods with slashes and appending “.to”.  For example, “gui.graphics.point” becomes “gui/graphics/point.to”.
  2. This relative pathname is applied to each of the following directories in turn until a file is found:
    1. the directory in which the current template source file resides
    2. the directories specified in the EVLTMPLPATH environment variable (a colon-delimited list of directories).  If the EVLTMPLPATH environment variable is not defined, the directories /var/evlog/templates/$LANG and /var/evlog/templates are searched, in that order.
  3. The selected template file is read into memory if it is not already there.

 

It is neither necessary nor permitted to import a template with the same name as one previously defined in the current template source file, unless the imported template is from a different directory.  For example, the following sequence of statements is illegal

      struct statusRegister;

      [definition of struct statusRegister’s attributes and format]

      END

      import statusRegister;  /* ILLEGAL */

 

However, the following sequence of statements is legal:

      struct statusRegister;

      [definition of struct statusRegister’s attributes and format]

      END

      import chipSet.fpu.statusRegister;  /* LEGAL [unless chipSet/fpu specifies the current directory] */

      import chipSet.fpu.dataRegisters;

      ...

      attributes {

            struct statusRegister cpuStatus;    /* refers to struct defined in this file */

            struct chipSet.fpu.statusRegister fpuStatus;

            struct dataRegisters dataRegs;

      }

      ...

 

6.1.2.2.2         Using formatting templates with POSIX_LOG_STRING and POSIX_LOG_NODATA

 

When using formatting templates with log_format of POSIX_LOG_NODATA, the "record attributes" section will be omitted, but the other 4 sections (imports/typedefs, header, const attributes, and template formatting specification) can still be used, and can reference attributes in the fixed portion of the event record.

 

When using formatting templates with log_format of POSIX_LOG_STRING, the "record attributes" section should specify a single attribute of type string -- for example:

 

     string      event_string;

 

"event_string" can then be referenced in the template formatting specification.

 

 

6.1.2.2.3        Advantages and Disadvantages

One advantage of the POSIX_LOG_BINARY data format is that only binary data values are stored in the event record, not formatting information, thus producing smaller event records.  Another advantage is that additional explanatory or suggested-action information can be included in the formatting templates, without increasing the size of the event records, or changing the software that logs the events.  The primary disadvantage is that formatting templates are stored separately from the code that logs the event, so there is a chance that the code and the template will get out of sync.

        

The creation, updating, and management of the formatting templates are described under FormattingTemplates and Formatting templates - Add/delete templates

 

6.2      Event Logging and Retrieval

6.2.1        Facility Registry

When events are written to the event log, one of the arguments that gets passed is facility.  The facility argument can be obtained by calling posix_log_strtofac() which converts a character string representation of facility into an integer representation, which is what actually gets stored into the event log.  posix_log_strtofac(), and posix_log_factostr() which converts integer to character string, both read from the file /var/evlog/facility_registry which has the following minimum entries, to support the minimum set of facilities specified by the POSIX standard (plus CRON and AUTHPRIV defined for syslog):

0      KERN 

8      USER

16    MAIL

24    DAEMON

32    AUTH

40    SYSLOG

48    LPR

56    NEWS

64    UUCP

72    CRON

80      AUTHPRIV     private     

88      FTP

96    LOGMGMT

128  LOCAL0

136  LOCAL1

144  LOCAL2

152  LOCAL3

160  LOCAL4

168  LOCAL5

176  LOCAL6

184     LOCAL7

Note that there is an additional parameter specified for "80  AUTHPRIV".  The parameter  "private" indicates that events logged with log_facility=AUTHPRIV will be written to a "private" log file,  /var/evlog/privatelog file.   If  this parameter is not set then events are logged to the standard active log file,  /var/evlog/eventlog.  Events cannot be logged to more than one log file.  "private" can be specified for multiple facilities.

The ability to write events to a private log instead of the standard log is modeled after the handling of syslog messages with facility of AUTHPRIV.   syslog.conf is frequently set up to write AUTHPRIV messages to /var/log/secure, while other messages are written to /var/log/messages (or destinations specified in /etc/syslog.conf).  This provides the ability to allow general read access for most messages but more restrictive read access for AUTHPRIV messages, as determined by the file permissions for the 2 (or more) message files.

Similar to the "private" parameter, another optional parameter, "kernel" may also be indicated.  For example:

0      KERN   kernel

The "kernel" parameter indicates that events logged by this facility will be logged from the kernel, as opposed to user-space.   If "kernel" is specified, and the associated event did not originate in the kernel, then the event will not be logged.   

 The facility codes match the corresponding definitions in sys/syslog.h, with the exception of LOGMGMT, which is not defined in syslog.h:

/* facility codes */

#define     LOG_KERN    (0<<3)      /* kernel messages */

#define     LOG_USER    (1<<3)      /* random user-level messages */

#define     LOG_MAIL    (2<<3)      /* mail system */

#define     LOG_DAEMON  (3<<3)      /* system daemons */

#define     LOG_AUTH    (4<<3)      /* security/authorization messages*/

#define     LOG_SYSLOG  (5<<3)      /* messages generated by syslogd */

#define     LOG_LPR     (6<<3)      /* line printer subsystem */

#define     LOG_NEWS    (7<<3)      /* network news subsystem */

#define     LOG_UUCP    (8<<3)      /* UUCP subsystem */

#define     LOG_CRON    (9<<3)      /* clock daemon */

#define     LOG_AUTHPRIV(10<<3)     /* security/authorization messages (private) */

#define     LOG_FTP     (11<<3)     /* ftp daemon */

 

      /* other codes through 15 reserved for system use */

#define     LOG_LOCAL0  (16<<3)     /* reserved for local use */

#define     LOG_LOCAL1  (17<<3)     /* reserved for local use */

#define     LOG_LOCAL2  (18<<3)     /* reserved for local use */

#define     LOG_LOCAL3  (19<<3)     /* reserved for local use */

#define     LOG_LOCAL4  (20<<3)     /* reserved for local use */

#define     LOG_LOCAL5  (21<<3)     /* reserved for local use */

#define     LOG_LOCAL6  (22<<3)     /* reserved for local use */

#define     LOG_LOCAL7  (23<<3)     /* reserved for local use */

 

A system that uses this event logging will probably add many more additional facilities to this registry to represent the entities in the system that will be logging events.  The evlfacility - Manage Facility Registry command is provided for Systems Administrators.  Additionally, functions are available in both kernel and user space for registering new facilities and obtaining facility integer values based on facility name.   See Registering Facilities and  7.5      Appendix F   Facility Names and Facility Code creation for more details.

 

6.2.1.1       Restricted Logging

 

In addition to the optional "private" and "kernel" parameters, an optional "restricted logging" filter can also be specified for any facility in the facility registry.   If a restricted logging filter is not specified for a facility, then all event records from that facility will be logged (unless discarded by another mechanism - see Screening of Events and Discarding duplicate events).  However, if a restricted logging filter is specified, then only event records with attribute values matching the filter will be logged.  To illustrate, see the following examples:

This entry in the facility registry…

136  LOCAL1   private    ' uid = "bsmith" && severity=INFO '

specifies that events from facilty LOCAL1 will only be logged if user id is "bsmith" and severity is INFO, and they will be written to the "private" log. 

In this example:

0xf39e1b2a   "My Facility"    ' log_format != BINARY '

specifies that events from facility "My Facility" will only be logged to the standard event log if variable-length data is NODATA or STRING.

The restricted logging filter is applied by the evlogd daemon (see Event Buffer and evlogd Daemon) before the event record is written to the log file.  Only attribute members from the fixed portion of the event record may be referenced in the filter.

 

6.2.2        evlogd Daemon  and Event Buffering

 

For events logged in user space the evlogd daemon (/usr/bin/evlogd) reads the events via socket from posix_log_write() and other user-space logging functions and writes the events into the standard event log (/var/evlog/eventlog), or alternately into the private event log (/var/evlog/privatelog) for facilities identified with the "private" option in the facility registry.  Events that are discarded either by the screening process (see Screening of Events), or by the discarding of duplicate events (see Discarding duplicate events), are not written to either log.

 

For events logged in the kernel the evlogd daemon forks a child process that reads events from the kernel event buffer via the ksyslog() system call and passes them to evlogd (via socket).  The child process will adjust the log_time value in the event record header if the EVL_INITIAL_BOOT_EVENT or EVL_KERNTIME_LOCAL bits are set in log_flags.  See 6.1.1        Fixed portion of Event Record for details.  evlogd also provides special handling of events associated with facility registration, as described under Registering Facilities from Kernel space.  evlogd writes events read from the kernel to one of the two log files (except for ones it discards) as described above.

 

The kernel event buffer is a static buffer with a default size of 128 Kbytes.  If required, the event buffer size can be changed during kernel configuration.  When the volume of incoming messages from posix_log_write() and other kernel logging functions completely fills the buffer faster than they can be read by evlogd, the most recently written events are discarded.  Once the overrun condition has been resolved, an event is logged indicating the total number of events that were dropped.

 

For example, assume that a flood of events results in 162 events being dropped, then viewing the event log with a filter of

facility == LOGMGMT  &&  event_type == EVL_BUFFER_OVERRUN

and displaying in compact mode, might show the following:

 

1453,43,POSIX_LOG_STRING,6,LOGMGMT,INFO,0,0,753,16,Sat Sep 15 11:32:31 2001,0,2,1,Discarded 162 events due to buffer overrun

 

During periods when the evlogd daemon is unable to gain exclusive access to /var/evlog/eventlog or /var/evlog/privatelog for writing event records, for example when the files are locked for log management, it allocates a temporary buffer to hold events (both kernel and user events).  When the locked file can be opened again by evlogd, the events are read from the buffer, written to the appropriate log file, and the buffer is freed. If the allocated buffer overflows before the events can be written to the log file(s) then the number of discarded events is counted and an event identical to the one described in the previous paragraph is logged.   

 

 

6.2.2.1       Screening of Events

 

The default behavior of the various write functions is as follows:

1.        All events written from the Kernel using the functions defined under Writing Events from Kernel Space, and events passed to printk(), are logged. 

2.        All events written by root (log_uid="root") are logged. 

3.        Events with log_facility of LOG_KERN will be logged if, and only if, they are written by the kernel or log_uid ="root".  This behavior cannot be modified.  If an illegal write of an event using LOG_KERN is attempted, the event will not be written to the kernel buffer, and whichever write function was called will return EPERM. 

4.        All events not covered by the preceding items, are logged. 

With the exception of item 3 above, the default behavior can be modified through use of the evlconfig command using the -screen option, which allows specifying which events logged from the kernel, by root, and from applications will be discarded.  To illustrate, defining the following screen:

evlconfig  -screen   uid = 0  &&  (facility = LPR  ||  severity = DEBUG)

specifies that events logged by root with facility of LPR, or with severity of DEBUG, will be discarded.

Note that all members of posix_log_entry (the fixed-portion of the event record) are valid for the -screen option.  See evlconfig - Configure logging daemon for more details.

An additional mechanism for discarding events is described under Discarding Duplicate Events.

 

6.2.2.2       Discarding duplicate events

 

An event is considered a duplicate if it is identical to the previous event, meaning that both the fixed portion, with the exception of log_time and log_recid, and the variable-length portion are the same.

   

When an event is to be logged, it is checked to determine if it is a duplicate of the previously logged event, based on the above definition.  If it is a duplicate, a duplicate-event counter will be incremented by 1, and the event will be discarded (purged from the event buffer and not written to the event log).  Also, if this is the first in this batch of discarded duplicates, a timer will be started (see item 3 below).

 

The discarding of duplicates continues until one of the following occurs:

 

  1. A different (not a duplicate) event is logged.
  2. The number of duplicate events matches the count specified with the evlconfig -dup_count command, or the default count.
  3. The time interval specified with the evlconfig -dup_time_int command, or the default time interval, has passed.

 

Note that if dup_time_int is set to 0, then step 3. does not apply.  Conversely, if dup_count is set to 0, then step 2. does not apply.  If both are 0, no duplicates are discarded, meaning all events are logged.

 

For all three cases, an event is logged that indicates the total number of duplicate events that were discarded, along with the event_type and facility.  Additionally, checking for duplicates is restarted (duplicate counter is reset to 0 and timer is cleared).[2]  

 

Discarding of duplicates can be switched on and off with the evlconfig -discard dups on | off command.

 

To illustrate, assume a duplicate-event count of 25, a time interval of 1 second, the logging of the same duplicate event at a rate of 30 events per second, and discarding of duplicates is enabled.  If all occurrences of the event in the log are displayed, by using a filter of

(facility == LOCAL1 || facility == LOGMGMT) &&

(event_type == 37 || event_type == EVL_DUPS_DISCARDED)

and displayed in compact mode, then the output might appear as follows:

 

1452,32,POSIX_LOG_STRING,37,LOCAL1,ERR,21924,3,753,16,

Thu Mar 15 19:32:31 2001,0,2,1

SCSI device 13 interface reset

 

1453,66,POSIX_LOG_STRING,7,LOGMGMT,INFO,0,0,753,16,

Thu Mar 15 19:32:31 2001,0,2,1

Discarded 25 duplicate events, event_type = 37, facility = LOCAL1

 

1454,32,POSIX_LOG_STRING,37,LOCAL1,ERR,21924,3,753,16,

Thu Mar 15 19:32:32 2001,0,2,1

SCSI device 13 interface reset

 

1453,66,POSIX_LOG_STRING,7,LOGMGMT,INFO,0,0,753,16,

Thu Mar 15 19:32:32 2001,0,2,1

Discarded 17 duplicate events, event_type = 37, facility = LOCAL1

 

1456,32,45,POSIX_LOG_STRING,37,LOCAL1,ERR,2324,6,2753,44,

Thu Mar 15 19:32:35 2001,0,1,1

Eth/0 interface reset by user

 

Note that the last event shown differs from the 44 events that preceded it, which were all duplicates.

 

It should also be noted that events which are written to the private log file, /var/evlog/privatelog, are also discarded by this mechanism.  See Facility Registry for more information on the private log file.

 

For more mores details on displaying events, see the evlview command.                                 

                                            

6.2.3        API Functions

6.2.3.1       Writing Event Records

Functions are provided for writing events to the event log from both user-space and from kernel-space. 

6.2.3.1.1        Writing Events from User Space

The POSIX standard provides posix_log_printf() for writing event records with log_format of POSIX_LOG_STRING from user-space.   It also provides posix_log_write(), where the log_format is specified, for logging from user-space.  An additional function is provided for writing event records with log_format of POSIX_LOG_BINARY, which is described below.

#include <posix_evlog.h>

#include <evlog.h>

int evl_log_write(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags, ...);

 

Used for writing event records with log_format of POSIX_LOG_BINARY, an alternative to posix_log_write() is provided where a variable-length argument list is passed instead of the address and length of a provider-allocated buffer.  Using this function, instead of posix_log_write(), removes the burden from the provider of allocating and subsequently freeing a buffer containing the variable-length data.

The evl_log_write() function determines from the variable argument list the size of the buffer to allocate, allocates and fills the buffer with the variable-length argument list, calls posix_log_write(), frees the buffer, and returns.

In order for evl_log_write() to allocate the correct buffer size, the optional attribute data type must be specified along with the optional attribute value, or values.   Valid data types are shown in the Table of Optional Attribute Data Types and Format Specifiers used with formatting templates, under Attribute Format.  Both single elements and arrays of elements may be specified.  The string "endofdata" must be used to indicate the end of the variable-length list.

 

If the variable-length data length exceeds LOG_ENTRY_MAXLEN, then the POSIX_LOG_TRUNCATE flag is set in log_flags and the data is truncated.

 

An example illustrates the required syntax, and ordering:

rc =  evl_log_write( facility, event_type, severity,

  "ushort", 0x1111,    /* type = unsigned short, value = 0x1111 */    

  "4*uchar", 5, 10, 15, 20,     /* 4 consecutive unsigned chars */

  "int[]", 10, int_array,       /* array of 10 ints */

  "string", "This is an example",

  "endofdata");

 

Values are packed into the buffer, with no pad bytes added for alignment.  Given the above example, on a 32-bit machine, the resulting buffer will be 65 bytes long: 2 for the ushort, 4 for the uchars, 40 for the int array, and 19 for the (null-terminated) string.

The flags argument contains application-defined flags.  The event record's log_flags member shall be set to the value of the flags argument.   evl_log_write() may also set the {POSIX_LOG_TRUNCATE} flag in the event record's log_flags member, as appropriate.  If the {POSIX_LOG_TRUNCATE} flag is set in the flags argument, it will also be set in the event record's log_flags member, even if evl_log_write() does not truncate the record.

 

 

Errors returned:

 

[EINVAL]              The facility argument is not a valid log facility.

 

[EINVAL]              The severity argument is invalid.

 

[EINVAL]              Arguments in the variable-length argument list are either invalid or not in the expected order, or an invalid number of arguments were passed.

 

[ENOSPC]              The event buffer has run out of space.

 

[EPERM]                The caller does not have the appropriate privilege for writing with the given facility.  Specifically, an application whose effective user ID is not root has attempted to log an event with a facility of LOG_KERN.

 

[EIO]                       An I/O error occurred.  This includes the event logging system not being configured.

 

 

 

#include <posix_evlog.h>

#include <evlog.h>

int evl_log_vwrite(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags, va_list args);

 

Identical to evl_log_write() with the exception that args is passed instead of a variable-length argument list. 

 

 

#include <posix_evlog.h>

int posix_log_vprintf(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags,

        const char *format, va_list args);

 

Identical to posix_log_printf(), described in the POSIX Spec., with the exception that args is passed instead of a variable-length argument list. 

 

 

 

6.2.3.1.2        Writing Events from Kernel Space

 

API functions that are analogous to posix_log_printf(), evl_log_write(), and posix_log_write()  are provided for writing events to the event log in kernel-space. 

 

#include <evl_log.h>

int posix_log_write(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, const void *buf, size_t len,

        int format, unsigned int flags);

 

This function has the same arguments, behavior, and returns (other than noted below) as posix_log_write() in user-space, which is defined in the draft POSIX standard.  Please refer to the POSIX event-logging specification referenced in Appendix A  POSIX 1003.25 **DRAFT** for a complete description of this function.

 

The following returns are not applicable to posix_log_write() in the kernel:

 

[EINVAL]              The facility argument is not a valid log facility.  

 

Any facility value is accepted; however, to avoid duplicate facility names between the kernel and user-space, facilities used in the kernel should be registered in the facility registry.  See Facility Registry for details.

 

[EMSGSIZE]         The len argument exceeds {POSIX_LOG_ENTRY_MAXLEN} length, and {POSIX_LOG_TRUNCATE} is not defined by the implementation.

 

POSIX_LOG_TRUNCATE is defined for this implementation.

 

              [EPERM]  The caller does not have the appropriate implementation-defined privilege for writing with the given facility.  For example, an application whose effective user ID is not root has attempted to log an event with a reserved facility code.

 

Any facility value is accepted .

 

              [ECANCELED]       The event-logging system has declined to log this event, for some implementation-defined reason.  For example, this event is a duplicate of another recently logged event, or the event-logging system has been configured to screen out events such as this one.

 

                                There are no implementation-defined reasons in this implementation.  Discarding of duplicates, for example, is performed by the evlogd logging daemon, not this function.

                               

              [EIO]     An I/O error occurred in writing to the system log. 

 

                                Not a valid return inside the kernel since event is only written to a buffer (unless it is full, then ENOSPC is returned).

 

     The following return exists only for posix_log_write() in the kernel, not in user-space.

 

              [ENOSYS]       Event logging is not configured in the kernel.

                               

 

 

#include <evl_log.h>

int posix_log_printf(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags, const char *format, ...);

 

This function has the same arguments, behavior, and returns (other than noted below) as posix_log_printf() in user-space, which is defined in the draft POSIX standard.  Please refer to the POSIX event-logging specification referenced in Appendix A  POSIX 1003.25 **DRAFT** for a complete description of this function.

 

The following returns are not applicable to posix_log_printf() in the kernel:

 

[EINVAL]              The facility argument is not a valid log facility.  

 

Any facility value is accepted; however, to avoid duplicate facility names between the kernel and user-space, facilities used in the kernel should be registered in the facility registry.  See Facility Registry for details.

 

               [EPERM]  The caller does not have the appropriate implementation-defined privilege for writing with the given facility.  For example, an application whose effective user ID is not root has attempted to log an event with a reserved facility code.

 

Any facility value is accepted .

 

              [ECANCELED]       The event-logging system has declined to log this event, for some implementation-defined reason.  For example, this event is a duplicate of another recently logged event, or the event-logging system has been configured to screen out events such as this one.

 

                                There are no implementation-defined reasons in this implementation.  Discarding of duplicates, for example, is performed by the evlogd logging daemon, not this function.

 

 

[EIO]     An I/O error occurred in writing to the system log. 

 

                                Not a valid return inside the kernel since event is only written to a buffer (unless it is full, then ENOSPC is returned).

 

     The following return exists only for posix_log_write() in the kernel, not in user-space.

 

              [ENOSYS]       Event logging is not configured in the kernel.

 

 

#include <evl_log.h>

int posix_log_vprintf(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags,

        const char *format, va_list args);

 

Identical to posix_log_printf(), with the exception that args is passed instead of a variable-length argument list. 

 

 

 

#include <evl_log.h>

evl_writek(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags, ...);

 

Used for writing event records with log_format of POSIX_LOG_BINARY,  the evl_writek() function determines from the variable argument list the size of the buffer to allocate, allocates and fills the buffer with the variable-length argument list, writes to the event buffer, and returns.

In order for evl_writek() to allocate the correct buffer size, the optional attribute data type must be specified along with the optional attribute value, or values.   Valid data types are shown in the Table of Optional Attribute Data Types and Format Specifiers used with formatting templates, under Attribute Format with the exception of float, double, ldouble, wchar and wstring, which are not supported.  Both single elements or arrays of elements may be specified.  The string "endofdata" must be used to indicate the end of the variable-length list.

 

If the variable-length data length exceeds LOG_ENTRY_MAXLEN then the POSIX_LOG_TRUNCATE flag is set in log_flags and the data is truncated.

 

All facility codes and event types will be accepted.   However, to avoid duplicate facility names between the kernel and user-space, facilities used in the kernel should be registered in the facility registry.  See Facility Registry for details.

 

Here is a sample call to evl_writek().  See the corresponding example in the description of the evl_log_write() function for an explanation of the argument list.

rc = evl_writek( facility, event_type, severity,

  "ushort", 0x1111,

  "4*uchar", 5, 10, 15, 20,

  "int[]", 10, int_array,

  "string", "This is an example",

  "endofdata");

The flags argument contains caller-defined flags.  The event record's log_flags member shall be set to the value of the flags argument.   evl_writek() may also set the {POSIX_LOG_TRUNCATE} flag in the event record's log_flags member, as appropriate.  If the {POSIX_LOG_TRUNCATE} flag is set in the flags argument, it will also be set in the event record's log_flags member, even if evl_writek() does not truncate the record.

 

 

 

Errors returned:

 

[EINVAL]              The severity argument is invalid.

 

[EINVAL]              Arguments in the variable-length argument list are either invalid or not in the expected order, or an invalid number of arguments were passed.

 

[ENOSPC]              The event buffer has run out of space.

 

[ENOSYS]              The event logging system is not configured.

 

 

#include <evl_log.h>

evl_vwritek(posix_log_facility_t facility, int event_type,

        posix_log_severity_t severity, unsigned int flags, va_list args);

 

Identical to evl_writek(), with the exception that args is passed instead of a variable-length argument list.

 

 

6.2.3.2       Formatting Event Records

 

#include <posix_evlog.h>

#include <evlog.h>

int evl_format_evrec_fixed(const  struct  posix_log_entry  *entry,  char *buf, size_t buflen,

        size_t *reqlen, const char *separator, size_t linelen,  int fmt_flags);

 

This function stores a character string describing the data contained in the fixed portion of the event record pointed to by entry into the buffer pointed to by the buf argument.

 

The buffer pointed to by buf is assumed to be at least buflen bytes long.  If buf is equal to NULL, or the buffer is too small to hold the returned character string, the function will fail.  In any case, if the reqlen argument is not NULL, the length in bytes required for the full character string will be stored in the location pointed to by reqlen.

 

The character string passed in the separator argument is used to delimit attributes that are written into buf.   If separator is NULL, no delimiter string is inserted between attributes.      

 

This function inserts newlines (\n) as necessary into the buf buffer to limit the maximum line length to linelen characters.  A linelen value of 0 indicates that there is no limit on the line length.  (If an attribute's value exceeds linelen characters, it will have a line to itself.)

 

The following  fmt_flags modify the character string written to the buffer:

 

EVL_COMPACT

 

Specifies that contents of the event record are written in a compact form.  This means that the attribute names for attributes in the fixed portion of the event record are not written, only the values.

 

                An example with a separator of ", " and linelen of 67:

 

recid=7214, size=31, format=POSIX_LOG_STRING, event_type=3, facility=LOCAL1, severity=ERR, uid=2324, gid=6, pid=2753, pgrp=44, time=Tue Jun 19 19:32:31 2001, flags=0, thread=-1, processor=1

     

An example of the COMPACT formatting, with a separator of "!" and a linelen of 0:

 

7214!31!POSIX_LOG_STRING!3!LOCAL1!ERR!2324!6!2753!44!Tue Jun 19 19:32:31 2001!0!-1!1    

 

Errors returned:

[EINVAL]     entry or buf are NULL

[EINVAL]     fmt_flags not equal to EVL_COMPACT, and not equal to 0.

[EINVAL}    separator is > 20 characters.

[EMSGSIZE] buf is too small to hold the string.

       

#include <posix_evlog.h>

#include <evlog.h>

int evl_format_evrec_variable(const struct posix_log_entry  *entry,  const void *var_buf, char *buf,      size_t buflen, size *reqlen);

This function stores a character string describing the data contained in the variable-length portion of the event record pointed to by var_buf into the buffer pointed to by the buf argument.

 

The buffer pointed to by buf is assumed to be at least buflen bytes long.  If  buf is equal to NULL, or the buffer is too small to hold the returned character string, the function will fail.  In any case, if the reqlen argument is not NULL, the length in bytes required for the full character string will be stored in the location pointed to by reqlen.

 

The actions performed are based on the log_format value:

·       POSIX_LOG_NODATA - If a formatting template exists, then applicable information read from the appropriate formatting template is copied into the buf buffer; otherwise, a null string is copied into buf.  

·         POSIX_LOG_STRING - If a formatting template exists, then applicable information read from the appropriate formatting template, in combination with the null-terminated string read from var_buf,, is copied into buf  (assuming that the string is referenced in the record attributes section of the template) ; otherwise, just the null-terminated string is copied into buf. 

·         POSIX_LOG_BINARY - If a formatting template exists, then variable-length data from var_buf is formatted based upon information read from the appropriate formatting template and copied into buf; otherwise, the variable-length data is formatted in dump format (displayed in HEX, with ASCII equivalent), for example:

 

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???

 

 

Errors returned:

[EINVAL]        buf,  entry or var_buf are NULL.

[EMSGSIZE]    buf is too small to hold string.

 

#include <posix_evlog.h>

#include <evlog.h>

int evl_format_evrec_sprintf(const struct posix_log_entry *entry,  const void *var_buf, const char *format, char *buf, size_t buflen, size *reqlen);

This function stores a character string describing the data contained in the event record pointed to by entry (the fixed portion) and var_buf  (the variable-length portion) into the buffer pointed to by the buf argument.  

 

The desired formatting is specified in the format argument.

 

Standard attributes are referenced using the attribute names defined in the POSIX standard:

recid, size, format, event_type, facility, severity, uid, gid, pid, pgrp, time, flags, thread, processor

For example, %recid% is replaced by the event record’s decimal record ID.

 

The pseudo-attribute “data” stands for entire variable-length portion of the event record.  The construct %data% is replaced by the string obtained by formatting this record using evl_format_evrec_variable() (see above).

 

The construct %attribute_name%, where attribute_name is the name of a non-standard attribute defined in this event record’s formatting template, is replaced by the formatted value of that variable.  attribute_name can be a simple name (e.g. “employee”) or a reference to a struct member (e.g. "employee.addr.city").

 

An attribute’s format can be overridden by appending a valid format specifier to the attribute name, separated by a ':' -- for example, %event_type:x%.

 

The buffer pointed to by buf is assumed to be at least buflen bytes long.  If  buf is equal to NULL, or the buffer is too small to hold the returned character string, the function will fail.  In any case, if the reqlen argument is not NULL, the length in bytes required for the full character string will be stored in the location pointed to by reqlen.

 

As an example, assume a formatting template like the one shown for event type 0x3115 under Formatting Template Example.  Given a format string defined as follows:

 

"Logical unit number is 0x%lun:x%\nfor facility %facility% and event type of  %event_type% decimal, 0x%event_type:x% hex\n"

 

The result stored in buf is:

 

Logical unit number is 0x3

for facility LOCAL1 and event type of 12565 decimal, 0x3115 hex

 

 

Errors returned:

[EINVAL]         entry, var_buf or buf are NULL

[EINVAL]         format is equal to NULL.

[EMSGSIZE]    buf is too small to hold the string.

[EBADMSG]    format references an attribute which does not exist.

 

#include <posix_evlog.h>

#include <evlog.h>

int evl_atttostr(const char *attribute, const struct posix_log_entry *entry, const void *var_buf, char *buf, size_t buflen, size_t *reqlen);

 This function stores a null-terminated character-string representation of an attribute value into the buffer pointed to by buf.  The value is taken from the event record whose fixed and variable parts are pointed to by entry and  var_buf, respectively.  The attribute's name is attribute.

The attribute is formatted according to the rules specified for evl_format_evrec_sprintf().

The buffer pointed to by buf is assumed to be at least buflen bytes long.  If  buf is equal to NULL, or the buffer is too small to hold the returned character string, the function will fail.  In any case, if the reqlen argument is not NULL, the length in bytes required for the full character string will be stored in the location pointed to by reqlen.

 

 

Errors returned:

[EINVAL]         buf or entry is NULL.

[EINVAL]         var_buf is NULL, and log_format is not POSIX_LOG_NODATA.

[EINVAL]         attribute is invalid, or does not exist in this event record.

[EMSGSIZE]    buf is too small to hold the string.

 

6.2.3.3       Formatting Templates

 

The formatting template example describes the information that is contained in a particular template.

Like C modules, formatting templates exist in two forms: source and binary.  A template source file that contains n template specifications will yield n binary template files when it is compiled using the evltc command.  Compilation of a template source file occurs in two steps:

1.        Parsing the template specification(s), as with the evl_parsetemplates() function

2.        Creating the binary file for each template, as with the evl_writetemplates() function

This is essentially what the evltc template compiler does.  These two functions are described in the “Template Management” section that follows.

API functions for template application are provided to:

·         Read the template's binary information, and return a pointer to a master evltemplate_t object.

·         Make one or more clones of a master evltemplate_t object.

·         Populate an evltemplate_t clone object with an event record's optional attributes (either initially, or to update the previous optional attributes with the most recent ones).

·         Use the evltemplate_t object to examine an event record's attributes.

 

6.2.3.3.1        The Template Repository

By default, the template repository is the directory /var/evlog/templates.  The evl_readtemplate() function, which loads an event-record template into memory, looks for that template in the binary file “/var/evlog/templates/facility/eventtype.to” where facility is the canonical facility name (see 7.5      Appendix F   Facility Names and Facility Code creation), and eventtype is the hexadecimal event type.  For the default template for facility facility, the binary template file is named default.to.  If the EVLTMPLPATH environment variable is set (and contains a colon-delimited set of directory paths), evl_readtemplate() will search those directories instead of  /var/evlog/templates.  If EVLTMPLPATH is not set, but the LANG environment variable is set, templates will be sought in /var/evlog/templates/$LANG first, then /var/evlog/templates.

The algorithm for finding a struct template that is referenced by another template is described under “More on Importing Templates” in the description of a template source file.  This algorithm is also affected by the EVLTMPLPATH environment variable.

When a template source file is compiled, the resulting binary files are created in the same directory as the source file.  Within a binary file, all struct references are relative, not absolute.  Therefore, it is possible to build a set of template binary files in one location (specified by the EVLTMPLPATH variable), and then move them (with or without the source files) to /var/evlog/templates.

 

6.2.3.3.2   Notes on template Use in Multithreaded Applications     

The functions in the “Compiling Templates” section are not intended to be thread-safe.  Using these functions in one thread, while another thread uses these same functions and/or the functions in the “Template Application” section, will produce undefined results.

 

The functions in the “Template Application” section are intended to be thread-safe in an application that uses POSIX threads.  Keep in mind, however, that if you pass the TMPL_REUSE1CLONE flag to evltemplate_initmgr(), all subsequent calls to evl_readtemplate() that request a clone of a particular template will return pointers to the same clone.  Therefore, take care when using the TMPL_REUSE1CLONE option in multithreaded applications.

 

Also keep in mind that functions such as the following may call functions in the “Template Application” section in order to obtain information about non-standard attributes in a record: posix_log_seek(), posix_log_query_match(), evl_format_evrec_variable(), evl_format_evrec_sprintf(), evl_atttostr().

 

6.2.3.3.3        Compiling Templates

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_parsetemplates(const char *source_filename, evltemplate_t *template_list[ ], size_t listsize,

size_t *ntemplates, FILE *errorfile, const char *prog_name);

 

This function reads the template specification(s) contained in the file whose pathname is source_filename.  Each template specification is checked for errors.  If errorfile is not NULL, error messages (if any) are written to errorfile.  Certain types of error messages are prefixed with the specified program name, prog_name -- e.g., “evltc”.

For each template specification that is successfully parsed, a pointer to the corresponding template object is stored in the template_list array.  listsize specifies the capacity of the array (i.e., the number of elements).  Upon return, *ntemplates is set to the number of successfully parsed templates.

The following types of errors are detected:

o        Syntax error

o        Facility, event_type, or struct name missing or invalid

o        A struct without attributes

o        Problems with an attribute’s name, type, dimension, or format

o        Const attribute value missing or incompatible with type

o        Invalid attribute reference in format section

o        Reference to a nonexistent struct template

o        Multiple instances of the same template (e.g., the source file contains multiple templates for struct x)

If there is at least one valid template specification, and no errors are detected, evl_parsetemplate() returns 0; otherwise it returns one of the following error codes:

[EINVAL]              The source_filename argument does not specify a readable file.

 

[EINVAL]              template_list is NULL, or ntemplates is NULL, or prog_name is NULL.

 

[EBADMSG]         Syntax error in template information; error messages are written to errorfile.

 

[EMSGSIZE]         template_list is not big enough to hold pointers to all the templates in the source file; that is, ntemplates exceeds listsize.

 

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_writetemplates(const char *directory, const evltemplate_t *template_list[ ], size_t listsize);

 

templatelist is an array of pointers to unpopulated templates, as returned by evl_parsetemplates().  listsize is the number of templates in the array.  This function writes each template to a binary template file in the directory whose pathname is directory.  Any existing file by that name is overwritten.

The name of a struct-template file is structname.to, where structname is the name of the struct.  The name of an event-record template is eventtype.to, where eventtype is the decimal event type.  If eventtype  is negative, the minus sign (-) is converted to an equals sign (=).

evl_writetemplates() returns 0 on success, or the indicated error code if one of the following errors is detected.  evl_writetemplates() stops writing files when it detects an error, but does not attempt to restore or remove files written before the error was detected.

 

[EINVAL]              template_list is NULL, or listsize is zero.

 

[ENOTDIR]           directory does not specify an existing directory.

 

[EPERM]                The caller does not have the appropriate privilege to write the desired template file(s).

 

[EIO]                       Some other error occurred while trying to write a template file.

 

6.2.3.3.4        Template Application

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_readtemplate(posix_log_facility_t facility, int event_type, evltemplate_t **template, int clone);

This function loads into memory a copy of the template for the specified facility and event type, and stores a pointer to that template at the location pointed to by template.  If this template references one or more struct templates (i.e., because this template has attributes of type struct), those templates will also be loaded into memory if they are not already present.

 

If the value of clone is zero, the resulting template will be the master template for this facility and event type.  If the master template for this facility and event type already exists in memory, evl_readtemplate() will return a pointer to that template.  The master template cannot be populated; it must first be cloned (using evl_clonetemplate()), and the resulting clone can be populated.

 

If the value of clone is non-zero, the resulting template will be a clone, as created by evl_clonetemplate(), and template->tm_master will point to the master template.  If the TMPL_REUSE1CLONE flag was passed to the template manager via evltemplate_initmgr(), and a clone of this template already exists in memory, evl_readtemplate() will return a pointer to that clone; otherwise a new clone will be created.

 

If there is no template specifically designated for the indicated facility and event type, but there is a default template for that facility, that default template will be provided.  As with other templates, only one master copy of a facility’s default template will be created, even if it is accessed via multiple evl_readtemplate() calls with different event types.  Similarly, if the TMPL_REUSE1CLONE flag is set in the template manager, there will be only one clone of the default template (unless you create others explicitly using evl_clonetemplate()).

 

evl_readtemplate() returns 0 on success, or the indicated error code if one of the following errors is detected.

 

[ENOENT]             There is no binary template file for the specified facility and event type, and there is no default template for that facility.

 

[EIO]                       The binary template file exists but cannot be successfully loaded.

 

[EINVAL]              template is NULL.

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_clonetemplate(evltemplate_t *master, evltemplate_t **clone);

This function creates a clone of the specified master template, and stores a pointer to the clone at the location pointed to by clone.  Any number of clones may be created from the same master template in this way.  Master templates are created using evl_readtemplate().

evl_clonetemplate() returns 0 on success, or the indicated error code if one of the following errors is detected.

 

[EINVAL]              master is NULL or clone is NULL .

 

[EINVAL}              master points to a clone template rather than a master.

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_populatetemplate(evltemplate_t *template, const posix_log_entry *entry, const void *buf);

This function populates the template object pointed to by template with values from the event record pointed to by entry (the fixed portion of the record) and buf (the optional portion).  The length, in bytes, of the buffer pointed to by buf is assumed to be entry->log_size.

 

template should have been previously created via evl_clonetemplate(), or via evl_readtemplate() with clone != 0 .  If it is currently populated, it will be depopulated before being repopulated with the new values.

 

It is not considered an error if the template implies that buf should contain more or less than entry->log_size bytes of data.  If buf contains more data than is implied by the template, the extraneous data will be stored in an attribute of type char[_R_] with the name _EXTRA_DATA_.  If buf contains insufficient data, the latter attributes in the template will be marked as empty.  If a scalar attribute is only partially filled when the end of buf is reached, that attribute will be marked as empty, and the leftover bytes will be stored in the _EXTRA_DATA _ attribute.  A partially filled struct or array will contain some populated elements and some empty ones.

 

If the data in buf implies that an array attribute has a negative size, the array will be treated as if it has a size of zero.

 

The populated template object contains references to the memory areas pointed to by entry and/or buf.  Therefore, if the contents of these areas are changed after the call to evl_populatetemplate(), subsequent references to the populated template (other than to depopulate or destroy the template) will produce undefined behavior.

 

Errors returned:

[EINVAL]              template or entry is NULL

[EINVAL]              template points to a master template rather than a clone.

 

#include <posix_evlog.h>

#include <evl_template.h>

int evl_depopulatetemplate(evltemplate_t *template);

The evl_depopulatetemplate() function disconnects the template object pointed to by template from its associated event record, reversing the effect of the previous evl_populatetemplate() operation on that template object.

 

Calling evl_depopulatetemplate() with a depopulated template object has no effect.

 

Errors returned:

 [EINVAL]             template is NULL, or appears to point to an invalid template object.

#include <posix_evlog.h>

#include <evl_template.h>

int evl_freetemplate(evltemplate_t *template);

The evl_freetemplate() function deallocates the template object pointed to by the template argument.  If the template object is populated (i.e., via evl_populatetemplate()), it will be depopulated before it is deallocated.

 

Since a master template shares a portion of its data structure with all its clones, it is illegal to deallocate a master template before deallocating all its clones.

 

Errors returned:

 [EINVAL]             template is NULL, or points to a master template with one or more existing clones.

#include <posix_evlog.h>

#include <evl_template.h>

int evl_releasetemplate(evltemplate_t *template);

 The evl_releasetemplate() function specifies that the indicated template can be released for reuse.  If the template is populated, it will be depopulated, unless the TMPL_LAZYDEPOP flag was passed to the template manager via evltemplate_initmgr().  If the template is a clone, and the TMPL_REUSE1CLONE flag was passed to the template manager, the template will be retained in memory; otherwise evl_releasetemplate() will attempt to free it by calling evl_freetemplate().

 

Errors returned:

 [EINVAL]     template is NULL, or points to a master template with one or more existing clones.

#include <posix_evlog.h>

#include <evl_template.h>

int evltemplate_initmgr(int flags);

The evltemplate_initmgr() function initializes this process’s template manager and specifies management options. The flags argument is the bitwise OR of zero or more of the following flags:

·         TMPL_REUSE1CLONE -- specifies that for a particular facility and event type, the same clone will be used all the time; each call to evl_readtemplate() with clone != 0 will return a pointer to this clone.  If this flag is not set, evl_releasetemplate() will free the specified clone, and evl_readtemplate() will create a new clone.

·         TMPL_LAZYDEPOP -- specifies that evl_releasetemplate() will not depopulate the specified clone.  This can be useful if the clone might be reused in its populated state.

For example, posix_log_query_match() may cause a clone template to be populated with a particular event record.  Before returning, posix_log_query_match() calls evl_releasetemplate().  If the TMPL_REUSE1CLONE and TMPL_LAZYDEPOP flags are set, the template will stay in memory and remain populated.  Subsequent code might then use the clone without repopulating it.

 

NOTE: To verify that a clone is populated with the correct event record, verify the following:

·         The clone’s tm_recid field matches the record ID of the desired record.

·         The clone’s tm_entry field is equal to the address of the record’s posix_log_entry struct.

·         The clone’s tm_data field is equal to the address of the record’s variable data.

 

By default (i.e, before evltemplate_initmgr() is first called), the TMPL_REUSE1CLONE and TMPL_LAZYDEPOP flags are cleared in the template manager.   A process must not call evltemplate_initmgr() more than once.

 

Errors returned:

 [EINVAL]     flags contains an illegal value.

 [EINVAL]    This function has been called previously.

 

#include <posix_evlog.h>

#include <evl_template.h>

int evltemplate_getatt(const evltemplate_t *template, const char *attribute_name, evlattribute_t **attribute);

attribute_name is the name of an attribute in the template object pointed to by template.  attribute_name can be a simple name (e.g., “employee”) or a reference to a struct member (e.g., “employee.addr.city”).  However, it cannot reference an array element (e.g., “widgets[2]” or “endPoints[1].y”).

The evltemplate_getatt() function stores a pointer to this attribute in the location pointed to by attribute.  The template may be master or clone, and may be populated or unpopulated.

Errors returned:

[EINVAL]              template does not point to a valid template.

[EINVAL]              attribute_name is NULL, or attribute is NULL.

 [ENOENT]            The template contains no attribute whose name is attribute_name.  The value of attribute is unchanged.

 

#include <posix_evlog.h>

#include <evl_template.h>

int evlatt_getstring(const evlattribute_t *attribute, char *buf, size_t buflen)

attribute is a pointer to an attribute in a template, as returned by evltemplate_getatt()or evltemplate_getatts(). The evlatt_getstring() function stores the string representation of that attribute’s value in the buffer pointed to by buf.  The buffer’s size in bytes is assumed to be buflen.  If the attribute's string representation would exceed buflen bytes, the copy is truncated to buflen bytes (including the terminating null character), and EMSGSIZE is returned.

If the specified attribute is empty (i.e., lacking a value in the associated event record), buf[0] is set to the null character to indicate a zero-length string.  This will always be the case for a non-const attribute in an unpopulated template.

Errors returned:

[EINVAL]              template does not point to a valid template.

[EINVAL]              attribute is NULL, or buf is NULL.

[EMSGSIZE]         The buffer length (as specified by buflen) is insufficient to hold the returned character string.

#include <posix_evlog.h>

#include <evl_template.h>

int evlatt_getinfo(const evlattribute_t *attribute, evlatt_info_t *info)

attribute is a pointer to an attribute in a template, as returned by evltemplate_getatt() or evltemplate_getatts(). The evlatt_getinfo() function stores the information about this attribute in the structure pointed to by info.  This structure has the following members:

typedef struct evlatt_info {

      unsigned int      att_flags;        /* flags defined below */

const char        *att_name;

int               att_type;         /* e.g., TY_INT, TY_STRING */

int               att_isarray;      /* 1 = array */

int               att_dimfixed;     /* # elements in fixed-size array */

int               att_dimpop;       /* # elements in populated array */

} evlatt_info_t;

 

The att_flags member may include the following flags:

·         EVL_ATTR_CONST – The attribute is a const attribute.

·         EVL_ATTR_BITFIELD – The attribute is a bit-field.

·         EVL_ATTR_EXISTS – The attribute has a value.  EVL_ATTR_CONST implies EVL_ATTR_EXISTS.  For a non-const attribute, EVL_ATTR_EXISTS will not be set if the template is not populated or the attribute lacks a value in the associated event record.

The att_name member points to the attribute’s name in the template object itself, and so should not be freed or otherwise modified by the caller.

If the attribute is not an array, the att_isarray, att_dimfixed, and att_dimpop members are all set to zero.  Otherwise, att_isarray is set to 1, and  att_dimfixed and att_dimpop have the following values:

·         If the template specifies that the array has a fixed number of elements, att_dimfixed contains that number, whether or not the template is populated, and whether or not the record (if any) actually contains the entire array.  Otherwise, att_dimfixed is -1.

·         If the EVL_ATTR_EXISTS flag is set for this attribute, att_dimpop contains the number of elements in the populated array.  Otherwise, att_dimpop is -1.

The att_type member specifies the base type of the attribute: one of the type codes listed in the following table.  To obtain the value of the attribute, use the function indicated in the table, passing the address of the evlattribute_t object.  Note that these functions cannot be used to extract values from arrays.

Type Code

Type

Function to Obtain Value

TY_CHAR, TY_SHORT, TY_INT, TY_LONG

char, short, int, long

long evl_getLongAttVal(att)

TY_UCHAR, TY_USHORT, TY_UINT, TY_ULONG

unsigned char, unsigned short, unsigned int, unsigned long

unsigned long evl_getUlongAttVal(att)

TY_LONGLONG

long long

long long evl_getLonglongAttVal(att)

TY_ULONGLONG

unsigned long long

unsigned long long evl_getUlonglongAttVal(att)

TY_ADDRESS

void *

void *evl_getAddressAttVal(att)

TY_FLOAT, TY_DOUBLE

float, double

double evl_getDoubleAttVal(att)

TY_LONGDOUBLE

long double

long double evl_getLongdoubleAttVal(att)

TY_STRING

char *

char *evl_getStringAttVal(att)

TY_STRUCT

struct

none

 

For an attribute of type struct, a pointer to the attribute’s struct template can be obtained using the evlatt_getstructtmpls() function, which see.

For an attribute that is an array of structs, the function evlatt_getstructfromarray() (which see) can be used to obtain a pointer to a populated struct template that represents a selected element of that array.

For other array attributes, the function evl_getArrayAttVal(att) returns a pointer to the first byte of that array in the event record.

Errors returned:

 [EINVAL]             attribute is NULL or info is NULL.

#include <posix_evlog.h>

#include <evl_template.h>

int evltemplate_getatts(const evltemplate_t *template, evlattribute_t *buf[ ], unsigned int bufatts, unsigned int *natts);

This function is like evltemplate_getatt(), except that it returns pointers to evlattribute_t objects for all attributes in the indicated template (which may be master or clone, populated or unpopulated).  buf points to an array into which evltemplate_getatts() will store the evlattribute_t pointers, and bufatts is the number of such pointers that the buffer can hold.

If buf is NULL or the number of attributes in the template exceeds bufatts, evltemplate_getatts() will fail.  In any case, if natts is not NULL, *natts will be set to the total number of attributes in the template.

For attributes of type struct, evltemplate_getatts() returns an evlattribute_t pointer for the struct itself (e.g. “startPoint”), but not for its component attributes (e.g., “startPoint.x”, “startPoint.y”).  The evlatt_getstructtmpls() function can be used to examine the template(s) corresponding to that attribute.

For an array attribute (including an array of structs), only one evlattribute_t object is returned; it describes the array itself.

Errors returned:

[EINVAL]              template does not point to a valid template.

[EINVAL]              buf is NULL, or bufatts is zero.

[EMSGSIZE]         The template contains more than bufatts attributes.

#include <posix_evlog.h>

#include <evl_template.h>

int evlatt_getstructtmpls(const evlattribute_t *attribute, const evltemplate_t **master, const evltemplate_t **clone);

attribute is a pointer to an attribute in a template, as returned by evltemplate_getatt() or evltemplate_getatts().  The base type of the attribute must be TY_STRUCT, and the attribute must not be an array.

If master is not NULL, a pointer to the master template for that struct is stored to the location pointed to by master.

If clone is not NULL, then a pointer to the populated clone template containing the component values for attribute is stored to the location pointed to by clone.  If attribute has no value (e.g., because it is part of a master template, or because it is an unpopulated attribute in a clone), NULL will be stored to the location pointed to by clone.

Errors returned:

[EINVAL]              attribute does not point to a non-array attribute whose base type is TY_STRUCT.

[EINVAL]              Both master and clone are NULL.

#include <posix_evlog.h>

#include <evl_template.h>

int evlatt_getstructfromarray(const evlattribute_t *att, int index, const evltemplate_t **tmpl);

att is a pointer to an attribute in a populated template, as returned by evltemplate_getatt() or evltemplate_getatts().  The attribute must be an array of structs.  index selects an element in this array.  *tmpl is set to point to the populated template that represents that particular element.

Errors returned:

[EINVAL]              att does not point to an attribute that is an array of structs.

[EINVAL]              att points to an unpopulated (or otherwise empty) array.

[EINVAL]              tmpl is NULL.

[EINVAL]              index is less than zero.

[ENOENT]             There is no element in the array with index = index.

 

6.2.3.4   Registering Facilities

 

6.2.3.4.1    Registering Facilities from User space

 

#include <evl_log.h>

int evl_register_facility( const char *fname, posix_log_facility_t  *fcode )

If the facility registry already contains a facility whose name is fname, set fcode to the corresponding code. 

If the facility registry does not contain a facility whose name is fname, compute the facility code as the 32-bit CRC of the canonical equivalent of fname, and set fcode to the computed value.  Add fname and fcode to the facility registry, unless there is already a facility in the registry with the same code as fcode, in which case return EEXIST. 

See 7.5      Appendix F   Facility Names and Facility Code creation for more details on facility code generation from canonical name.

   Errors returned:

[EINVAL]   fname or fcode are NULL

[EINVAL]   fname length is zero, or greater than POSIX_LOG_MEMSTR_MAXLEN

[EEXIST]   fcode generated from fname already exists in the facility registry.

[EPERM]    The caller does not have the appropriate privilege to register a facility.

[EAGAIN]   Insufficient system resources are available.  Try again.

 

#include <evl_log.h>

int evl_gen_facility_code( const char *fname, posix_log_facility_t  *fcode )

If fname is the upper or lower case name of a standard Linux facility, fcode is set to the corresponding facility code.  The standard facility names and facility codes are listed under 6.2.1        Facility Registry.

If fname is not a standard Linux facility, compute the facility code as the 32-bit CRC of the canonical equivalent of fname.  If the resulting code is the same as one of the standard facilities, return EEXIST; otherwise, set fcode to the computed value.

See 7.5      Appendix F   Facility Names and Facility Code creation for more details on facility code generation from canonical name.

Errors returned:

[EINVAL]   fname or fcode are NULL