Kittyfisto / Tailviewer

Open source log file viewer
https://kittyfisto.github.io/Tailviewer/
MIT License
200 stars 37 forks source link

Allow custom log levels #184

Open Kittyfisto opened 5 years ago

Kittyfisto commented 5 years ago

Current behaviour

Tailviewer currently only supports a fixed set of log levels (Debug, Info, Warn, Error, Fatal) which are a carbon copy of Log4Net's levels. It should at least be possible to configure (application-wide) the actual spelling of those log levels.

For example a user should be able to customize the "Info" log level to actually spell "Information" and have Tailviewer search for "Information" when testing if a log line is of that type.

Requirements

Kittyfisto commented 5 years ago

TODO:

In the future, this very same mechanism can be used in order to allow loading newer plugin versions at runtime.

atabaksahraei commented 4 years ago

That is a really important feature for us. I changed in LogLine.DetermineLevelsFromLine the loglevel strings and it worked. It would be nice to setup those strings in Settings!

Kittyfisto commented 4 years ago

That is a really important feature for us. I changed in LogLine.DetermineLevelsFromLine the loglevel strings and it worked. It would be nice to setup those strings in Settings!

I'll try to schedule it as close as possible then :) In the meantime, you can also achieve this by writing a plugin and I'd be happy to show you.

arnereinelt commented 4 years ago

In the meantime, you can also achieve this by writing a plugin and I'd be happy to show you.

Which interfaces must be implemented for such a plugin: ILogLineTranslator or anything else?

Kittyfisto commented 4 years ago

@arnereinelt You will have to implement both ILogLineTranslator and IFileFormatPlugin2 (or IFileFormatPlugin depending on your needs).


public sealed class MyCustomLogLevelTranslator
    : ILogLineTranslator
{
    #region Implementation of ILogLineTranslator

    public LogLine Translate(ILogFile logFile, LogLine line)
    {
        line.Level = GetLogLevel(line.Message);
        return line;
    }

    private LevelFlags GetLogLevel(string lineMessage)
    {
        if (lineMessage.IndexOf("FAT", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Fatal;
        if (lineMessage.IndexOf("ERR", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Error;
        if (lineMessage.IndexOf("WARN", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Warning;
        if (lineMessage.IndexOf("INF", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Info;
        if (lineMessage.IndexOf("DBG", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Debug;
        if (lineMessage.IndexOf("TRA", StringComparison.CurrentCulture) != -1)
            return LevelFlags.Trace;

        return LevelFlags.None;
    }

    #endregion
}

The IFileFormatPlugin implementation then needs to instantiate the log line translator implementation so tailviewer makes use of it:

ILogFile IFileFormatPlugin.Open(IServiceContainer services, string fileName)
{
    // Registering an instance which implements ILogLineTranslator causes
    // the call to CreateTextLogFile to use this translator to translate every
    // reported log line, allowing a plugin to:
    // - Change the content being displayed
    // - Parse metadata, thereby allowing tailviewer to properly interpret the log file
    //   - Parsing timestamps allows treating multiple lines as a single log entry
    //   - Parsing timestamps allows multiple log files to be merged into chronological order
    //   - Parsing log levels allows highlighting log entries and easy filtering by log level
    services.RegisterInstance<ILogLineTranslator>(new MyCustomLogLevelTranslator());

    return services.CreateTextLogFile(fileName);
}

I'm currently writing and testing an example (the code above has been written from memory, but should work) and will update this thread once it's done.

arnereinelt commented 4 years ago

Very well. It works. Many thanx for your prompt reply.

Kittyfisto commented 4 years ago

You're very welcome. I'm glad it's already working for you!

In case anybody else is interested, I've just added an example plugin implementation which shows exactly what needs to be implemented in order to get this to work: https://github.com/Kittyfisto/Tailviewer/tree/master/examples/Tailviewer.LogLevelPlugin.

arnereinelt commented 4 years ago

@Kittyfisto BTW, how can I make a plugin's icon displayed in tailviewer?

Kittyfisto commented 4 years ago

@Kittyfisto BTW, how can I make a plugin's icon displayed in tailviewer?

I assume you mean in the plugins page? In this case you can you this by invoking "archive.exe" with the additional "icon" command-line parameter when packing the plugin:

archive.exe pack myplugin.dll --icon e:\0tNyzgK.jpg

The path you specify as an icon can be either relative to the current directory or an absolute path as shown above. From memory, I think most common image formats should work (jpg, png, maybe ico can't remember right now :P).

arnereinelt commented 4 years ago

Fine, fine, fine. Works as expected, even with macro for the path. Mille grazie.