Introduction
Easy Log Viewer is a tool which helps developers to easier view logs, it contains these features:
1: Support all kinds of logs, ( Windows Event Log, CSV Logs, XML logs, text logs, database logs ...).
- Open Window Event Log (Application).
- Open CSV file:
- Open XML file
- Open Text file:
2: Easy to filter and search , I guess nobody want the viewer doesn't support this feature.
Click Find Previous or Find Next to navigate between Find what:
3: The feature should powerful, should support Contains, NotContains, StartsWith, Equal, Regex... , So I can easier to filter logs.
4: highligh based on filters, Sometimes I want to highlight the interest items.
5: hide or show some log records, This will allow me to focus on the log which I interested in.
6: Bookmark support. Like Visual Studio , navigation in bookmark is easier.
7: Annotation support, Sometimes I want to add some comments to log, so when I send them to others, other can see my comments.
8: Save the log, It should save the log and the settings of the Log.
9: The UI should be stupid and simple, and powerful, It should be easy to use, and easy to rearrange, and support full screen mode.
Free Style
Full Screen Mode
Background
There're lots of logging framework, like log4j, log4net, NLog, Microsoft Enterprise Logging Framework...
These logging frameworks help developer to Log messages in application, with these frameworks, You can log your messages to DB, to Console, to File, to other computers, to what ever you want.
However I found there is NO Log Viewer Tool which support all kinds of logging targets.
Some tool only support one kinds of Logging format, and some doesn't have the feature I want, That's why I created this tool!.
Using the code
EasyLogViewer support plugin,
For example, if you want to read your log entries from other places,
- Create a project , and add reference to EasyLogViewer.IHandler.dll
- Implement the
IReadLogFileHandler
interface,
- Put the build bin folder to Plugins folder, like other plugin does.
namespace EasyLogViewer.IHandler
{
public interface IReadLogFileHandler : IBaseHandler
{
object Execute(string fileName, Action<IEnumerable<ExpandoObject>> newLogEntriesCallback, HandledEventArgs args);
}
}
Below is an example of how to write a text file reader:
public class LineFileHandler : IReadLogFileHandler
{
public int Priority
{
get { return Int32.MinValue; }
}
public object Execute(string fileName, Action> newLogEntriesCallback,HandledEventArgs args)
{
var result = new List<ExpandoObject>();
using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var sr = new StreamReader(fs))
{
while (sr.Peek() >= 0)
{
dynamic obj = new ExpandoObject();
obj.Message = sr.ReadLine();
result.Add(obj);
}
}
}
args.Handled = true;
return result;
}
}
Your plugin will be executed by PluginManager
class.
public static class PluginManager
{
private static readonly Dictionary<object, object=""> pluginCache = new Dictionary<object, object="">();
private static readonly List<type> pluginTypes = new List<type>();
public static void LoadPlugins()
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
LoadPlugins(assembly);
}
string[] pluginFolders = Directory.GetDirectories("Plugins");
foreach (string pluginFolder in pluginFolders)
{
string[] files = Directory.GetFiles(pluginFolder, "*.dll");
foreach (string file in files)
{
Assembly assembly = Assembly.LoadFrom(Environment.CurrentDirectory + "\\" + file);
//Assembly assembly = AppDomain.CurrentDomain.Load(Environment.CurrentDirectory + "\\" + file);
LoadPlugins(assembly);
}
}
}
public static object RunPlugins<t>(this object owner, params object[] handleArgs) where T : IBaseHandler
{
object result = null;
var eventArgs = new HandledEventArgs(false);
List<object>newArgs = handleArgs.ToList();
newArgs.Add(eventArgs);
object[] combineArgs = newArgs.ToArray();
List<t> handlers = GetPlugins<t>(owner);
MethodInfo methodInfo = null;
foreach (T handler in handlers)
{
try
{
if (methodInfo == null)
{
methodInfo = typeof(T).GetMethod("Execute");
}
if (eventArgs.Handled == false)
{
result = methodInfo.Invoke(handler, combineArgs);
if (eventArgs.Handled)
{
EventLogHelper.LogInformation(string.Format("Parse Log Success {0}", handler));
}
}
else
{
break;
}
}
catch (Exception ex)
{
//swallow this exception, do the next parser.
EventLogHelper.LogError("This plugin has error,...", ex);
}
}
return result;
}
private static List<t> GetPlugins<t>(object owner) where T : IBaseHandler
{
if (!pluginCache.ContainsKey(owner) ||
!pluginCache[owner].OfType<t>().Any())
{
List<type> matchPluginTypes = pluginTypes.Where(t => t.Implements<t>()).ToList();
List<object> plugins =
(from matchPluginType in matchPluginTypes
where matchPluginType.IsClass
select Activator.CreateInstance(matchPluginType)).ToList();
pluginCache[owner] = plugins;
}
return pluginCache[owner]
.OfType<t>()
.OrderByDescending(t => t.Priority)
.ToList();
}
private static void LoadPlugins(Assembly assembly)
{
IList<type> types = assembly.TypesImplementing<ibasehandler>();
foreach (Type type in types)
{
pluginTypes.Add(type);
}
}
}
Please notice the RunPlugins<T>
method, this method will pass the parameters to plugin, and run the Execute method by reflection.
So what's next?
Features still outstanding for EasyLogViewer:
- Export logs in several formats (CSV, XML,...).
- Highlight the method Enter and Exit,
- Group methods.
- Group filters, so filters can And/Or.
- Column Display Plugin.
- Quick navigate between find logs.
- Got any ideas you'd like to share? Ping me.
Points of Interest
http://logging.apache.org/log4net/
http://nlog-project.org/
History
30 May 2015: Version 1.0