smtlog.c


/*  ----------------------------------------------------------------<Prolog>-
    Name:       smtlog.c
    Title:      SMT logging agent
    Package:    Libero/SMT Kernel 2.x

    Written:    1996/06/15  iMatix SMT kernel team smt@imatix.com
    Revised:    1999/11/26

    Synopsis:   Writes data to log files.

    Copyright:  Copyright (c) 1991-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SMT License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "smtdefn.h"                    /*  SMT definitions                  */


/*- Definitions -------------------------------------------------------------*/

#define AGENT_NAME   SMT_LOGGING        /*  Our public name                  */
#define LOG_LINEMAX  4096

typedef struct                          /*  Thread context block:            */
{
    int  handle;                        /*    Handle for i/o                 */
    Bool timestamp;                     /*    By default, we timestamp       */
} TCB;


/*- Function prototypes -----------------------------------------------------*/

static char *logfile_name (THREAD *thread);
static void  open_logfile (THREAD *thread, char mode);
static char *time_str     (void);


/*- Global variables used in this source file only --------------------------*/

static TCB
    *tcb;                               /*  Address thread context block     */
static QID
    console;                            /*  Operator console event queue     */

#include "smtlog.d"                     /*  Include dialog data              */


/********************   INITIALISE AGENT - ENTRY POINT    ********************/

/*  ---------------------------------------------------------------------[<]-
    Function: smtlog_init

    Synopsis: Initialises the SMT logging agent.  Returns 0 if initialised
    okay, -1 if there was an error.  The logging agent writes data to log
    files.  Create an unnamed thread for each log file you want to manage,
    then send events to that thread.  Supports these public methods:
    <Table>
    CYCLE       Cycle log file if it already exists.
    OPEN        Start a new logfile as specified by event body.
    APPEND      Append to an existing logfile as specified by event body.
    PUT         Write line to logile, prefixed by date and time.
    PLAIN       Use plain logfile output (no timestamp).
    STAMP       Put timestamp at start of each logged line.
    CLOSE       Close logfile and destroy thread.
    </Table>
    Sends errors to the SMTOPER agent; does not send reply events.
    ---------------------------------------------------------------------[>]-*/

int
smtlog_init (void)
{
    AGENT   *agent;                     /*  Handle for our agent             */
    THREAD  *thread;                    /*  Handle to console thread         */
#   include "smtlog.i"                  /*  Include dialog interpreter       */

    /*                      Method name   Event value     Priority           */
    /*  Shutdown event comes from Kernel                                     */
    method_declare (agent, "SHUTDOWN",    shutdown_event, SMT_PRIORITY_MAX);

    /*  Public methods supported by this agent                               */
    method_declare (agent, "CYCLE",       cycle_event,    0);
    method_declare (agent, "OPEN",        open_event,     0);
    method_declare (agent, "APPEND",      append_event,   0);
    method_declare (agent, "PUT",         put_event,      0);
    method_declare (agent, "PLAIN",       plain_event,    0);
    method_declare (agent, "STAMP",       stamp_event,    0);
    method_declare (agent, "CLOSE",       close_event,    0);

    /*  Ensure that operator console is running, else start it up            */
    smtoper_init ();
    if ((thread = thread_lookup (SMT_OPERATOR, "")) != NULL)
        console = thread-> queue-> qid;
    else
        return (-1);

    /*  Signal okay to caller that we initialised okay                       */
    return (0);
}


/*************************   INITIALISE THE THREAD   *************************/

MODULE initialise_the_thread (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */
    tcb-> handle    = 0;                /*  File is not open                 */
    tcb-> timestamp = TRUE;             /*  By default, we timestamp         */
    the_next_event = ok_event;
}


/************************   CYCLE LOGFILE IF EXISTS   ************************/

MODULE cycle_logfile_if_exists (THREAD *thread)
{
    char
        *name;

    if ((name = logfile_name (thread)) != NULL)
        file_cycle (name, CYCLE_ALWAYS);
}

static char *
logfile_name (THREAD *thread)
{
    char
        *name;

    tcb = thread-> tcb;                 /*  Point to thread's context        */
    /*  Event body or thread name supplies name for the log file             */
    if (thread-> event-> body && strused (thread-> event-> body))
        name = (char *) thread-> event-> body;
    else
        name = thread-> name;

    if (streq (name, "") || streq (name, "NULL"))
        return (NULL);
    else
        return (name);
}


/**************************   OPEN THREAD LOGFILE   **************************/

MODULE open_thread_logfile (THREAD *thread)
{
    open_logfile (thread, 'w');
}

static void
open_logfile (THREAD *thread, char mode)
{
    char
        *name;

    tcb = thread-> tcb;                 /*  Point to thread's context        */

    if ((name = logfile_name (thread)) == NULL)
        tcb-> handle = 0;
    else
      {
        tcb-> handle = lazy_open_text (name,
                       mode == 'w'? O_WRONLY | O_CREAT | O_TRUNC:
                       mode == 'a'? O_WRONLY | O_CREAT | O_APPEND:
                       /*  else  */ O_WRONLY | O_CREAT);
        if (io_completed)
            if (tcb-> handle < 0)       /*  If the open failed, send error   */
              {                         /*    to console, and terminate      */
                sendfmt (&console, "ERROR", "Could not open %s", name);
                senderr (&console);
                raise_exception (exception_event);
              }
      }
}


/*************************   APPEND THREAD LOGFILE   *************************/

MODULE append_thread_logfile (THREAD *thread)
{
    open_logfile (thread, 'a');
}


/************************   LOG FILE OUTPUT IS PLAIN   ***********************/

MODULE log_file_output_is_plain (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */
    tcb-> timestamp = FALSE;            /*  No timestamp in data             */
}


/************************   LOG FILE OUTPUT IS TIMED   ***********************/

MODULE log_file_output_is_timed (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */
    tcb-> timestamp = TRUE;             /*  Add timestamp to data            */
}


/*************************   WRITE TEXT TO LOGFILE   *************************/

MODULE write_text_to_logfile (THREAD *thread)
{
    static char
        formatted [LOG_LINEMAX + 1];    /*  Formatted string                 */
    word
        size,                           /*  Size of event body               */
        source;                         /*  Copy text from event body        */
    int
        fmtsize;                        /*   into the formatted string       */

    tcb = thread-> tcb;                 /*  Point to thread's context        */

    if (tcb-> timestamp)
      {                                 /*  Start with date and time         */
        strcpy (formatted, time_str ());
        strcat (formatted, ": ");       /*  Add a colon and a space          */
        fmtsize = strlen (formatted);   /*    and add event body text        */
      }
    else
        fmtsize = 0;                    /*  No date/time stamp               */

    size = thread-> event-> body_size;
    if (thread-> event-> body [size - 1] == '\0')
        size--;

    for (source = 0; source < size; source++)
      {
        formatted [fmtsize++] = thread-> event-> body [source];
        if (fmtsize == LOG_LINEMAX)
            break;
      }
    formatted [fmtsize++] = '\n';       /*  Add a newline                    */

    /*  Write to the log file, but do not try to signal errors - if we       */
    /*  send a message to the console now, we could create an infinite       */
    /*  loop... (the console may send it right back to us, see?)             */

    if (tcb-> handle)
        lazy_write (tcb-> handle, formatted, fmtsize);
}


/*  -------------------------------------------------------------------------
 *  time_str
 *
 *  Returns the current date and time formatted as: "yy/mm/dd hh:mm:ss".
 *  The formatted time is in a static string that each call overwrites.
 */

static char *
time_str (void)
{
    static char
        formatted_time [18];
    time_t
        time_secs;
    struct tm
        *time_struct;

    time_secs   = time (NULL);
    time_struct = safe_localtime (&time_secs);

    sprintf (formatted_time, "%2d/%02d/%02d %2d:%02d:%02d",
                              time_struct-> tm_year % 100,
                              time_struct-> tm_mon + 1,
                              time_struct-> tm_mday,
                              time_struct-> tm_hour,
                              time_struct-> tm_min,
                              time_struct-> tm_sec);
    return (formatted_time);
}


/**************************   CLOSE THREAD LOGFILE   *************************/

MODULE close_thread_logfile (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */

    if (tcb-> handle)                   /*  Close log file, if opened        */
        lazy_close (tcb-> handle);
}


/*************************   TERMINATE THE THREAD   **************************/

MODULE terminate_the_thread (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */
    the_next_event = terminate_event;
}

Generated by Framer 1.0 © 1997 iMatix