HP Software Developers Blog
HP Software Developers thought leadership around software architecture and design, cloud data modeling, mobile technologies, big data, performance programming and more.

The Log visualization framework

Log visualization / Pablo Retyk

 

As developers, we incorporate logging (or tracing) in our software as part of the regular development process. This logging information allows us to diagnose problems in our software, especially when they happen in a non-debugging environment (usually at the customer’s site).

Today, there are several frameworks to write logs and tracing, using different techniques such AOP, instrumentation, Event Logging API’s, and so forth.

In this post, I would like to present a new approach I created for facilitating a rapid view and analysis of the log regarding the object states. As we know, many bugs are caused by invalid object states, and usually cannot be seen in the logs unless we write them explicitly. Using the VisualLogs framework (currently for .NET, coming soon for Java), in an Aspect Oriented way, you can mark your classes for Visualization by using the VisualLog and VisualLogDescription attributes seen in the example below:

public class Store
    {
        private List<Customer> _customers = new List<Customer>();
	//Orders will be exposed in the visualization of Store
        [VisualLog]
        private List<Order> _orders = new List<Order>();
        private List<Item> _items = new List<Item>();

        public void AddCustomer(Customer customer)
        {
            if (!_customers.Contains(customer))
            {
                _customers.Add(customer);
            }
        }

        public void AddItem(Item item)
        {
            if (!_items.Contains(item))
            {
                _items.Add(item);
            }
        }

        public void AddOrder(Order order)
        {
            _orders.Add(order);
            AddCustomer(order.Customer);
            AddItem(order.Item);
        }
    }

    public class Customer
    {
        public Customer(string name)
        {
            Name = name;
        }
	//The Name property of customer is used in the Visualization Description
        [VisualLogDescription]
        public string Name { get; private set; }
    }

    public class Order
    {
        public Order(Customer customer, Item item, int quantity)
        {
            Customer = customer;
            Item = item;
            Quantity = quantity;
        }

        [VisualLog]
        public Customer Customer { get; private set; }
        [VisualLog]
        public Item Item { get; private set; }
        [VisualLog]
        public int Quantity { get; set; }

	//The ToString method of customer is used in the Visualization Description
        [VisualLogDescription]
        public override string ToString()
        {
            return string.Format("Order: {0}  {1}", Quantity, Item.Name);
        }
    }

    public abstract class Item
    {
        protected Item(string name)
        {
            Name = name;
        }
//The Name property of Item is used in the Visualization Description
        [VisualLogDescription]
        public string Name{get ;set ;}
    }

    public class Book : Item
    {
        public Book(string name) : base(name)
        {
            
        }
    }

    public class Phone : Item
    {
        public Phone(string name) : base(name)
        {
            
        }
    }
}

 

The use of the logs will be like this:

    class Program
    {
        private static void Main(string[] args)
        {
            Logger.Info("Some info log");
            Logger.Info("Creating a store");
            var store = new Store();
            Logger.Debug("Adding orders");
            store.AddOrder(new Order(new Customer("Walter"),new Book("Harry Potter"),2));
            store.AddOrder(new Order(new Customer("Gustavo"),new Book("Romeo and Juliet"),3));

	    //Visualize Store
            Logger.VisualizeObject(store);

            Logger.Debug("Adding more orders");
            store.AddOrder(new Order(new Customer("Mike"), new Phone("LG"), 4));
            store.AddOrder(new Order(new Customer("Jesse"),new Phone("Samsung"),5));
            store.AddOrder(new Order(new Customer("Soul"),new Book("Don Quixote"),6));
            Logger.Debug("Finishing adding orders");
            Logger.VisualizeObject(store);
            Logger.Debug("Exiting.....");
        }
    }

 

This is how the log looks (best viewed with Chrome or Firefox)

logVis1.png

 

Take into account that using this kind of log in a production environment can affect the performance. As a result, it is recommended to be used only for diagnostics purposes, so you can check the log level before calling the visualization as follows:

public static void VisualizeObject(object o)
        {
            if (_log.Logger.IsEnabledFor(Level.Verbose))
            {
                var visualizer = Visualizer.Svg;

                var objVisualization = visualizer.Visualize(o);
                _log.Debug(objVisualization);
            }
        }

 

For this example I integrated the VisualLogs framework with log4net. However this can be used with any framework or as standalone tool.

 

About the project

The attributes mentioned above are used to extract the set of properties and fields that describe the object dependencies. Then, a reflection of the object and all its dependencies is created recursively as shown below: 

 

internal class ReflectedObject : IObjectDescriptor, IEquatable<ReflectedObject>
    {
        public ReflectedObject(object obj)
        {
            _object = obj;

            var type = obj.GetType();
            _fieldsAndProperties = type.GetMembers(...);
            var innerObjectsMemberInfo = _fieldsAndProperties.Where(prop => prop.IsDefined(typeof(VisualLogAttribute), false));
            foreach (var innerObjectMemberInfo in innerObjectsMemberInfo)
            {
	      //Get all innerObjects recursively		
                var objectToReflect = GetObjectFromType(innerObjectMemberInfo, _object);
                ...
                
                    if (objectToReflect is IEnumerable)
                    {
                        foreach (var objectItem in (IEnumerable)objectToReflect)
                        {
                            _innerReflectedObjects.Add(new ReflectedObject(objectItem));
                        }
                    }
                    else
                    {
                        _innerReflectedObjects.Add(new ReflectedObject(objectToReflect));
                    }
                
            }
        }









        public string Description
        {
            get
            {
                if (string.IsNullOrEmpty(_description))
                {
                    var descriptionMember =
                        _fieldsAndProperties.FirstOrDefault(
                            prop => prop.IsDefined(typeof (VisualLogDescriptionAttribute), false));


                    object description = GetObjectFromType(descriptionMember, _object);
                    _description = description == null
                                       ? _object.ToString()
                                       : string.Format("{0}({1})", _object.GetType().Name, description);
                }

                return _description;
            }
        }

 

and added to a dependency graph, using this code:

internal class SvgVisualizer : VisualizerBase
{
	public override string Visualize(object objectToVisualize)
	{
	...
var graph = FactoryProvider.CreateStringGraph();
            FactoryProvider.CreateGraphCreator().Create(objectToVisualize, graph);
            var graphviz = new GraphvizAlgorithm<string, TaggedEdge<string, string>>(graph.ToQuickGraph())
                {
                    ImageType = imageType
                };


            graphviz.Generate(…);
	}
            
 }       

 

This graph is later transformed using Quickgraph to transform the graph into Graphviz format This then can be converted to Svg format and read by a HTML5 compatible browser.

You can access the full source code here: https://github.com/pablito900/VisualLogs

 

 

 

Leave a Comment

We encourage you to share your comments on this post. Comments are moderated and will be reviewed
and posted as promptly as possible during regular business hours

To ensure your comment is published, be sure to follow the Community Guidelines.

Be sure to enter a unique name. You can't reuse a name that's already in use.
Be sure to enter a unique email address. You can't reuse an email address that's already in use.
Type the characters you see in the picture above.Type the words you hear.
Search
Showing results for 
Search instead for 
Do you mean 
About the Author
I've been all over the coding world since earning my degrees have worked several years in c++ and then several in java, finally setteling i...
Featured


Follow Us
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation.