Custom Tabs - Glimpse/Glimpse GitHub Wiki
Tabs are used in the Glimpse client to logically separate diagnostics data and provide for extensibility. Out of the box, we supply a number of tabs, but its incredibly easy to create your own tabs.
Here we are looking at how you create your own tabs, showing the data that you care about.
##Simple Tab
The Glimpse team ships tabs useful for ASP.NET WebForms and ASP.NET MVC development which are all available on GitHub.
The following is a simple sample tab which lists out all configured HTTP Modules for a given web application:
using System;
using System.Collections.Generic;
using Glimpse.AspNet.Extensibility;
using Glimpse.AspNet.Extensions;
using Glimpse.Core.Extensibility;
namespace Glimpse.Tab.Sample
{
public class Modules : AspNetTab
{
public override object GetData(ITabContext context)
{
var result = new List<object>();
var httpContext = context.GetHttpContext();
foreach (var key in httpContext.ApplicationInstance.Modules.AllKeys)
{
result.Add(new {
Index = result.Count + 1,
Name = key,
Type = httpContext.ApplicationInstance.Modules[key].GetType().FullName
});
}
return result;
}
public override string Name
{
get { return "Module"; }
}
}
}
###Details
Glimpse tabs are implementations of the ITab interface, or the TabBase or AspNetTab abstract base classes.
-
TabBasesimply selects a few common default configuration options for a tab, and -
AspNetTabdoes the same for tabs specifically targeting the ASP.NET runtime.
If we take a look at what ITab asks us to implement, the following is what we defined:
-
Name { get; }- Used as the label of the tab in the Glimpse client and theGetDatamethod returns the data to be displayed inside of said tab. -
GetData(...)- Can return any arbitrary object (graph) and Glimpse will do its best to render the output in a sensible fashion.
##Optional Enhancements
Glimpse tabs can be enhanced to provide a better user experience in many different ways. None of the following are required, but are all nice touches.
###Documentation Link - DocumentationUri
Each tab can provide a contextual help button to its users.
The help button is only rendered when the tab also implements the IDocumentation interface and provides a DocumentationUri.
using Glimpse.Core.Extensibility;
namespace Glimpse.Tab.Sample
{
public class CustomTab : ITab, IDocumentation
{
public string DocumentationUri
{
get { return "http://somesite.com/help/customTab"; }
}
...
}
}
Tab authors can feel free to host their tab's documentation on getGlimpse.com. Simply update the documentation wiki and ask for the content to be deployed.
###Pivot Layout - ILayoutControl
This extension provides the means by which you tell Glimpse to treat the keys of the root object returned as section headings rather than what would normally be rendered. You can indicate this intent by implementing the ILayoutControl interface.
using Glimpse.Core.Extensibility;
namespace Glimpse.Tab.Sample
{
public class Modules : ITab, ILayoutControl
{
public bool KeysHeadings
{
get { return true; }
}
}
}
###Control Layout - ITabLayout
Out of the box, Glimpse tries to layout your data based on the "shape" of the data. If you don't like how it looks out of the box, you can control the layout of the tab by implementing the ITabLayout interface.
using System.Collections.Generic;
using Glimpse.Core.Extensibility;
namespace Glimpse.Tab.Sample
{
public class Modules : ITab, ITabLayout
{
private static readonly object Layout = new object[] {
new object[]
{
new { Data = "key", Width = "200px", Key = true },
new { Data = "value" },
new { Data = "{{assembly}}::{{type}}", Class = "mono" }
}
};
public object GetLayout()
{
return Layout;
}
public override object GetData(ITabContext context)
{
return new List<object>
{
new {Key = "test", Value = "Value", Assembly = typeof(int).Assembly.FullName,
Type = typeof(int)},
new {Key = "test", Value = "Value", Assembly = typeof(string).Assembly.FullName,
Type = typeof(string)},
new {Key = "test", Value = "Value", Assembly = typeof(double).Assembly.FullName,
Type = typeof(double)}
};
}
...
}
}
The full interface of what is supported, hasn't been fully documented yet. That said, the client rendering demo has lots of examples of what is possible.
###Setup Hook - ITabSetup
When creating more complex tabs, you may want to have code that wires up when your tab initilizes your tab. For the most part, this occurs when you want to pull messages of a given type from the message broker.
using Glimpse.Core.Extensibility;
using Glimpse.Core.Extensions;
namespace Glimpse.Tab.Sample
{
public class Modules : ITab, ITabSetup
{
public void Setup(ITabSetupContext context)
{
// Note: `PersistMessages<>()` is an extension message
context.PersistMessages<AdoMessage>();
}
...
}
}
###Key Generation - IKey
By default when Glimpse serializes the payload for a given tab, the "key" it will generate for a tab will be based on the full name of the type.
Sometimes, you may want to customize this name, to be something that is eaiser to refer to (mainly in cases where you want to lookup the data for the tab from a client plugin).
Implementing the IKey on your interface lets you control the key that is generated.
using Glimpse.Core.Extensibility;
namespace Glimpse.Tab.Sample
{
public class Modules : ITab, IKey
{
public string Key
{
get { return "my_modules"; }
}
}
}
###Customizing the RuntimeEvent from a tab
Sometimes you may want to customize to which event your tab hooks, this makes a difference when you try to access objects that can be disposed depending on the RuntimeEvent used. For example: if your tab tries to access the Session object from AspNet and you use the RuntimeEvent.EndRequest you will get a System.NullReferenceException because the session object is already disposed.
You can change the event of a custom tab overriding the ExecuteOn property:
public class MyMetadataTab : Glimpse.Mvc.Tab.Metadata
{
public override RuntimeEvent ExecuteOn
{
get { return RuntimeEvent.EndSessionAccess; }
}
}##More Examples
Here are some more examples of whats possible with creating different plugins,