windows-eventlog-reader

1.1.0 • Public • Published

windows-eventlog-reader

NOTE This module has not proved useful to myself or my colleagues who it was written for, so I have decided to no longer maintain this project. If you would like to take over maintenance of this project please let me know via stephen.vickers.sv@gmail.com. For the record, the following Microsoft Windows bug is the core reason I am no longer maintaining this project - this bug still seems to affect the Windows platforms I am targetting - https://support.microsoft.com/en-us/kb/177199.

This modules provides Node.js programs the ability to read events from a Windows event log.

This module is installed using node package manager (npm):

# This module contains C++ source code which will be compiled
# during installation using node-gyp.  A suitable build chain
# must be configured before installation.

npm install windows-eventlog-reader

It is loaded using the require() function:

var eventlog = require ("windows-eventlog-reader");

Individual logs can then be opened and tail'ed:

var reader = eventlog.createReader ("Application");

function feedCb (event) {
    console.dir (event);
}

function doneCb (error) {
    if (error)
        console.error (error.toString ());
}

reader.readAll (1, feedCb, doneCb);

reader.tail (1, function (error, event) {
    if (error)
        console.error (error.toString ());
    else
        console.dir (event);
});

Non-Blocking Operations

Windows event logs are typically stored in files on a hard disk. Opening and reading an event log involves reading these files from disk, and the Windows API to do so operates in a blocking mode, i.e. each read request will block the calling program from performing other operations. In the context of Node.js this will introduce a pause of an undefined amount of time into the Node.js event loop.

NOTE Although event log contents may come directly from the operating systems file/page cache, the blocking I/O side effect is still passed on to the calling program, i.e. something in the call chain may decide to block and a calling Node.js program cannot do anything about it. Also, to obtain formatted messages for each event log event, one or more DLL's need to be loaded directly from disk, which involves more blocking I/O.

This module utilises the libuv library to integrate into the Node.js event loop - this library is also used by Node.js. The libuv function uv_queue_work() is used to queue operations to run in the background. As a result this module will not block the Node.js event loop when blocking operations are performed.

There is one exception to this claim. The close() method exposed by this module is performed within the Node.js event loop. This function will call the Win32 API function CloseEventLog(), which might block. However, during development this function always seemed to return pretty much instantly.

Event Objects

This module uses JavaScript objects to represent events, for example:

{
    sourceName: 'gupdate',
    computerName: 'as00041.uk.internal',
    recordNumber: 6330,
    timeGenerated: 1372576636,
    timeWritten: 1372576636,
    eventId: 5104,
    eventType: 'Information',
    eventCategory: 0,
    message: 'Service started'
}

Each event object will have following parameters:

  • sourceName - String specifying the event source for the event, e.g. MSSQLServer
  • computerName - String specifying the computer on which the event was generated, e.g. sql-server.test.com
  • recordNumber - Identifies the event in this event log
  • timeGenerated - Instance of the JavaScript Date class specifying the date and time at which the event was generated
  • timeWritten - Instance of the JavaScript Date class specifying the date and time at which the event was actually written to the event log
  • eventId - Number specifying the event identifier, this is specifiec to the event source
  • eventType - String specifying event type, this can be one of Error, Warning, Information, AuditSuccess, AuditFailure or Unknown
  • eventCategory - Number specifying the event category, this is specific to the event source and is not defined by this module
  • message - String containing the formatted event message

Event identifiers, i.e. the eventId attribute, contain multiple sub-fields. Refer to Win32 API documentation for details on each field. To obtain the event code field, as it is displayed in the Windows event log viewer, bitwise & the eventId attribute with 0xffff:

var eventCode = event.eventId & 0xffff;

Error Handling

Each operation exposed by this module typically requires a mandatory callback function which will be called when an operation completes.

Callback functions are typically provided an error argument, and almost all errors are instances of the Error class.

In the event a Windows event log is cleared while a reader is reading from it the Win32 API will return the error code ERROR_EVENTLOG_FILE_CHANGED. In this case the error argument will be an instance of the eventlog.EventLogClearedError class.

This type of error will typically only occur for operations that involve a read from the event log, e.g. read() or tail().

If this error is experienced, the event log can be closed, re-opened, and the original request re-submitted:

var offset = 1;

function cb (error) {
    if (error) {
        // When an error occurs this operation will complete, and in the
        // case of an event log being cleared we want to re-open it and
        // re-submit our original request
        if (error instanceof eventlog.EventLogClearedError) {
            reader.close ();
            reader.open (function (error) {
                if (error)
                    console.error (error.toString ());
                else
                    reader.tail (offset, cb);
            });
        } else {
            console.error (error.toString ());
        }
    } else {
        offset = event.recordNumber;
        console.dir (event);
    }
}

reader.tail (offset, cb);

Using This Module

Event log readers are represented by an instance of the Reader class. This module exports the createReader() function which is used to create instances of the Reader class.

Readers can be used to read all or part of an event log, and to tail the event log and notify users of new events.

eventlog.createReader (name)

The createReader() function instantiates and returns an instance of the Reader class:

var reader = eventlog.createReader ("Application");

The name parameter is the name of the event log to create a reader for.

An exception will be thrown if the reader could not be created. The error will be an instance of the Error class.

After calling this function and creating a reader the underlying Windows event log will not have been opened. The open() method must be called on the reader for the underlying Windows event log to be opened.

NOTE When the open() method is called this module will use the Win32 API OpenEventLog() function. The documentation for this function states that if the event log could not be found then the Application event log will be opened instead.

reader.on ("close", callback)

The close event is emitted by the reader when the underlying event log handle is closed.

No arguments are passed to the callback.

The following example prints a message to the console when the reader is closed:

reader.on ("close", function () {
    console.log ("event log closed");
});

reader.open (callback)

The open() method opens the underlying Windows event log represented by the reader.

The callback function is called once the underlying Windows event log has been opened. The following arguments will be passed to the callback function:

  • error - Instance of the Error class or a sub-class, or null if no error occurred

The following example opens the Application Windows event log:

reader.open (function (error) {
    if (error)
        console.error (error.toString ());
});

reader.close ()

The close() method closes the underlying Windows event log represented by the reader.

NOTE This function will call the Win32 API function CloseEventLog(), which might block. However, during development this function always seemed to return pretty much instantly.

The following example opens the Application Windows event log:

reader.open (function (error) {
    if (error)
        console.error (error.toString ());
    else
        reader.close ();
});

reader.read (offset, feedCallback, doneCallback)

The read() method reads zero or more events from the underlying Windows event log.

The offset parameter specifies at what record number to start reading from (note that the event with this record number will also be returned if it exists).

This method will not call a single callback once some events have been read. Instead the feedCallback function will be called for each event read. The following arguments will be passed to the feedCallback function:

  • event - An object describing the event (see the "Event Objects" section for more information on event objects)

Once the read has completed, or an error has occurred, the doneCallback function will be called. The following arguments will be passed to the doneCallback function:

  • error - Instance of the Error class or a sub-class, or null if no error occurred

If the feedCallback function returns a true value when called no more events will be read or passed to the feedCallback function, and the doneCallback will be called.

Once the doneCallback function has been called the read is complete and the feedCallback function will no longer be called.

The following example reads a number of events starting at offset 1,000:

function feedCb (event) {
    console.dir (event);
}

function doneCb (error) {
    if (error)
        console.error (error.toString ());
}

var reader = eventlog.createReader (name);
var offset = 1000;

reader.open (function (error) {
    if (error) {
        console.error (error.toString ());
    } else {
        reader.read (offset, feedCb, doneCb);
    }
});

reader.readAll (offset, feedCallback, doneCallback)

The readAll() method reads zero or more events from the underlying Windows event log until no more events are available.

The offset parameter specifies at what record number to start reading from (note that the event with this record number will also be returned if it exists).

This method will not call a single callback once all events have been read. Instead the feedCallback function will be called for each event read. The following arguments will be passed to the feedCallback function:

  • event - An object describing the event (see the "Event Objects" section for more information on event objects)

Once the read has completed, or an error has occurred, the doneCallback function will be called. The following arguments will be passed to the doneCallback function:

  • error - Instance of the Error class or a sub-class, or null if no error occurred

If the feedCallback function returns a true value when called no more events will be read or passed to the feedCallback function, and the doneCallback will be called.

Once the doneCallback function has been called all available events will have been read and the feedCallback function will no longer be called.

The following example reads all events starting at offset 2,000:

function feedCb (event) {
    console.dir (event);
}

function doneCb (error) {
    if (error)
        console.error (error.toString ());
}

var reader = eventlog.createReader (name);
var offset = 2000;

reader.open (function (error) {
    if (error) {
        console.error (error.toString ());
    } else {
        reader.readAll (offset, feedCb, doneCb);
    }
});

reader.tail (offset, [interval], callback)

The tail() method periodically reads zero or more events from the underlying Windows event log as they become available.

The offset parameter specifies at what record number to start reading from (note that the event with this record number will also be returned if it exists). The optional interval parameter is the number of milliseconds between each read call, and defaults to 3000.

The callback function will be called as each event is read from the event log, or if an error occurs. The following arguments will be passed to the callback function:

  • error - Instance of the Error class or a sub-class, or null if no error occurred
  • event - An object describing the event (see the "Event Objects" section for more information on event objects)

NOTE If an error occurs the callback function will be called with the first error argument defined, and after the callback function returns the tail operation will be stopped.

If the callback function returns a true value when called no more events will be read, and the callback function will not be called again.

The following example reads all events starting at offset 6,000, and then tails the Windows event log, calling the cb function as and when events become available:

function cb (error, event) {
    if (error)
        console.error (error.toString ());
    else
        console.dir (event);
}

var reader = eventlog.createReader (name);
var offset = 6000;

reader.open (function (error) {
    if (error) {
        console.error (error.toString ());
    } else {
        reader.tail (offset, cb);
    }
});

Example Programs

Example programs are included under the modules example directory.

Bugs & Known Issues

None, yet!

Bug reports should be sent to stephen.vickers.sv@gmail.com.

Changes

Version 1.0.0 - 30/06/2013

  • Initial release

Version 1.0.1 - 01/07/2013

  • Add "Error Handling" section to the README.md file

Version 1.0.2 - 01/07/2013

  • Feed callback functions can return true to indicate an operation should stop feeding events
  • Silence some compilation warnings
  • Throw an exception when the event log name provided is not valid

Version 1.0.3 - 11/07/2013

  • Added eventId attribute to the event object
  • Added missing documentation for the close() method to the README.md file

Version 1.0.4 - 15/08/2013

  • Address various issues reported by cppcheck

Version 1.0.5 - 15/12/2014

  • Not initializing event log handle results in random invalid handle messages

Version 1.1.0 - 09/10/2015

  • Add note to the README.md that the project is no longer maintained

Roadmap

Suggestions and requirements should be sent to stephen.vickers.sv@gmail.com.

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses.

Author

Stephen Vickers stephen.vickers.sv@gmail.com

Package Sidebar

Install

npm i windows-eventlog-reader

Weekly Downloads

0

Version

1.1.0

License

GPL

Last publish

Collaborators

  • stephen.vickers