Fantom

 

const class

util::FileLogger

sys::Obj
  sys::ActorPool
    util::FileLogger
//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   8 Apr 08  Brian Frank  Creation
//

**
** FileLogger appends Str log entries to a file.  You
** can add a FileLogger as a Log handler:
**
**    sysLogger := FileLogger(scriptDir + `logs/sys.log`)
**    sysLogger.start
**    Log.addHandler |rec| { sysLogger.writeLogRec(rec) }
**
**
const class FileLogger : ActorPool
{

  **
  ** Constructor.
  **
  new make(|This|? f := null) { if (f != null) f(this) }

  **
  ** File to append log records.  This value can be
  ** configured as a const field, or by `open` method.
  **
  const File? file

  **
  ** Open the specified file to write for the file logger.
  ** The file is used instead of the `file` field.  This method
  ** must be called before attempting to write to the log.
  **
  Void open(File file)
  {
    actor.send(file)
  }

  **
  ** Append string log message to file.
  **
  Void writeLogRec(LogRec rec)
  {
    actor.send(rec.toStr)
  }

  **
  ** Append string log message to file.
  **
  Void writeStr(Str msg)
  {
    actor.send(msg)
  }

  **
  ** Run the script
  **
  internal Obj? receive(Obj msg)
  {
    // if file message, this is an open()
    file := this.file
    write := true
    if (msg is File)
    {
      file = msg
      write = false
      Actor.locals["error"] = null
    }

    // if we are in error condition ignore
    if (Actor.locals["error"] != null) return null

    // open file if first time thru
    OutStream? out := Actor.locals["out"]
    if (out == null)
    {
      // if no file configured
      if (file == null)
      {
        Actor.locals["error"] = true
        log.err("No file configured")
        return null
      }

      // open it to append
      try
      {
        if (!file.exists) file.create
        out = file.out(true)
        Actor.locals["out"] = out
      }
      catch (Err e)
      {
        Actor.locals["error"] = true
        log.err("Cannot open log file: $file", e)
        return null
      }
    }

    // append to file
    if (write) out.printLine(msg).flush

    return null
  }

  private const static Log log := Log.get("logger")
  private const Actor actor := Actor(this) |msg| { receive(msg) }

}