Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

tango.util.log.Log usage

Moderators: larsivi kris

Posted: 08/10/08 12:34:34

It took me quite some time to figure out how to use the new logging stuff in 0.99.7

Most of the examples of the reference documentation and the tutorial didn't seem to work anymore.

But once I found out, I think the new logging interface is much clearer and easier to use. Great work!

So here is a small example on how to log to stdout, how to use your own layout and how to convert the output to Ansi when logging to a file. Hope that helps.

Importing this module

/*******************************************************************************
    myLayout : Logger layout with ISO-date sans millisecs
    Output (optionally) translated to Ansi
    
    Basically stolen from tango.util.log.LayoutDate
*******************************************************************************/
module myLayout;

private import  tango.text.Util;
private import  tango.time.WallClock;
private import  tango.util.log.Log;
private import  tango.sys.win32.CodePage;
private import  Integer  = tango.text.convert.Integer;

public class myLayout : Appender.Layout
{
    private bool convertToAnsi;
    private static char[6] spaces = ' ';
    
    this (bool convertToAnsi = false)
    {
            this.convertToAnsi = convertToAnsi;
    }

    void format (LogEvent event, void delegate(void[]) dg)
    {
        char[] level = event.levelName;
        
        auto tm = event.time;
        auto dt = WallClock.toDate(tm);
                        
        char[16] tmp = void;
        char[256] tmp2 = void;
        dg (layout (tmp2, "%0-%1-%2 %3:%4:%5 %6%7 %8 - ", 
                    convert (tmp[0..4],   dt.date.year),
                    convert (tmp[4..6],   dt.date.month),
                    convert (tmp[6..8],   dt.date.day),
                    convert (tmp[8..10],  dt.time.hours),
                    convert (tmp[10..12], dt.time.minutes),
                    convert (tmp[12..14], dt.time.seconds),
                    spaces [0 .. $-level.length],
                    level,
                    event.name
                    ));
        
        convertToAnsi // Output Ansi? 
        ? dg (toAnsi(event.toString))
        : dg (event.toString);
    }

    private char[] convert (char[] tmp, long i)
    {
        return Integer.formatter (tmp, i, 'u', '?', 8);
    }

    // convert Utf-8 to Ansi
    private char[] toAnsi(char[] text)
    {
        char[1024] buffer = void;
        // if buffer is too small, allocate from heap
        if(text.length >= buffer.length) {
            scope buf_p = new char[](text.length + 1);
            return CodePage.into(text, buf_p).dup;
        }
        else {
            return CodePage.into(text, buffer).dup;
        }
    }
}

I use it like that

module  loglayout;

import  tango.util.log.Log;
import  tango.util.log.AppendConsole;
import  tango.util.log.AppendFile;
import  tango.io.Console;

import  myLayout;

void main(char[][] args)
{
    auto root  = Log.root;
    root.level = root.Trace;
    
    // Output to stderr using myLayout
    //root.add(new AppendConsole(new myLayout()));
    
    // Output to stdout using myLayout
    // (ala StdoutAppender of Tango 0.99.6)
    root.add(new AppendStream(Cout.stream, true, new myLayout()));
    
    // Output to file using myLayout and converted to Ansi
    root.add(new AppendFile("loglayout.log", new myLayout(true)));
    
    auto log = Log.lookup ("main");
    log.level = log.Trace;
    
    log.info  ("Hello");
    log.warn  ("German umlauts here '{}' and here '{}'", "ÄÖÜ", "äöü");
    log.error ("Oops!");
}

So here are my questions:

1. Is this how the logging system is meant to be used or am I totally misunderstanding it?

2. Using AppendConsole? under Windows, all (Utf-8) output is "magically" converted to the proper codepage. Very nice. But when the console output is redirected to a file, there is no conversion. Is there an easy way for a log appender to detect that the console output is redirected?

Author Message

Posted: 08/10/08 18:57:36

Yeah, that looks right. The principal functionality left unused is probably the hierarchy (of names) and the way appenders are associated and executed on nodes within the hierarchy. That is, while you have your example appenders attached to the root, they can instead be attached to any node in the tree where the tree itself is constructed through logger names.

For example, given two logs called "my.log" and "my.log.subordinate", all appenders attached to the former will be executed when the latter is invoked (assuming the warn/error/info filtering does not inhibit output). This notion applies to 'root' also, which is why root is often where all appenders are attached for the sake of simplicity.

With regard to file redirection: When utilizing Cout or Cerr in your appender, you can access the redirection status via a Cout.redirected() method, and adjust your processing accordingly.

Hope that helps

Posted: 08/10/08 23:17:58

kris wrote:

Yeah, that looks right. The principal functionality left unused is probably the hierarchy (of names) and the way appenders are associated and executed on nodes within the hierarchy. That is, while you have your example appenders attached to the root, they can instead be attached to any node in the tree where the tree itself is constructed through logger names.

Thank you very much.

I think I understood this part - how the logger crawls upwards from the leaf to the root to find the attached appender(s) - that didn't change from 0.99.6. But with only one main() and no functions/classes in my example...

kris wrote:

With regard to file redirection: When utilizing Cout or Cerr in your appender, you can access the redirection status via a Cout.redirected() method, and adjust your processing accordingly.

Hope that helps

I think so. I will have a look at this redirected() method.

Posted: 08/11/08 13:22:46

Hehe, that is cool!

So it's as easy as

    // Output to stdout using myLayout
    // (ala StdoutAppender of Tango 0.99.6)
    root.add(new AppendStream(Cout.stream, true, new myLayout(Cout.redirected())));

Thanks again.