5 Easy Methods for Improving Your Dashboards

Dashboards are important. Your NOC is an essential avenue for collecting and relaying information about your network, and combined with a finely crafted set of alerts there’s nothing that can get past you. Not only are dashboards effective, but they just look so stinkin’ awesome when done properly. In this post I’m going to focus on my ‘Dashboard Philosophy,’ which is all about efficiency, information, and design. A dashboard should display the most data possible in the space that you have, it should include pertinent information that summarizes your environment, and it should look good doing it. Let’s talk about what the SolarWindsRegistered OrionRegistered Platform brings to the table to help make our dashboards the best they can be.

  1. NOC Views

Using the NOC view feature is a must. These space-saving views allow you to combine multiple sub-views that can be set on a rotation. Creating one is easy: simply add a new summary view, edit it, then enable left navigation and the NOC view feature. Here you can enter an interval for how often the NOC view rotates between individual sub-views. If you aren’t using NOC views, you’re wasting valuable space on your dashboards! Enter NOC mode, full-screen your browser window, and bask in the glory of a massive canvas to display all your fancy metrics and charts. Rob Boss would be proud.

     2. Network Atlas

Admit it, you both love and hate Network Atlas. It’s an incredibly useful tool that requires a bit of extra patience, but the results can be amazing once you get the hang of it. As Henry David Thoreau probably once said, “SolarWinds Network Atlas is but a canvas for your imagination…” or something like that. Check out this amazing example from THWACKRegistered user spzander​:

pastedImage_17.png

Hungry for more? Here is some of my favorite THWACK content for tuning your Network Atlas skills and getting the creative juices flowing:

10 Hidden Gems in Orion Network Atlas

Using Custom Properties to send messages to your NOC using Network Atlas

The “Show us your Network Atlas Maps” thread

     3. PerfStack

With the release of NPM 12.1 came a game-changing new feature… PerfStackTm. This new charting tool allows you to quickly and easily create attractive charts that contain the data you need while optimizing page space. PerfStack is what makes you, the monitoring professional, shine when an application owner is looking for a way to view monitoring data for their systems. Check out the original release notes for PerfStack here. Since its first iteration, the SolarWinds team has been putting a lot of work into this tool. With PerfStack 2.0, they have added support for many major Orion modules including VMAN, SAM, VNQM, NCM, and DPA, along with a pile of new features such as fast polling, syslog/trap support, quick links, and full screen mode (which makes a great dashboard). As of this post, the next iteration of PerfStack is available in the latest NPM 12.3 Release Candidate and includes… drumroll please… A PERFSTACK WIDGET FOR YOUR DASHBOARDS!

pastedImage_18.png

Here we have a node detail view… WITH PERFSTACK! You can do the same thing with any view type in Orion, including Summary Views (which means dashboards). For dashboard nerds such as myself, this is truly a good day. Sign up for the NPM RC program for more details and awesome sneak peeks at what SolarWinds is doing to improve tools like PerfStack.

     4. AppStack

This is really one of the most efficient ways to display a mass amount of information in such a small space. AppStack is a one-size-fits-all tool that will satisfy your devs, their managers, and your director. An efficient dashboard should have MAXIMUM information in MINIMUM space, and AppStack is the answer. Whether you only have SAM or you’re running multiple products on the Orion platform the AppStack widget gives you a flexible, filterable, and fun-tastic (I couldn’t think of another word that started with ‘f’) resource to add to your dashboards and NOC views. There’s not much more to say. It’s the perfect widget for my Dashboard Philosophy.

pastedImage_19.png

     5. SWQL and Other Advanced Methods

Are you a dev nerd? Do you like to yell at code until it bends to your will? Are you ready to bring your SolarWinds deployment to an unreasonably awesome level? With a little bit of fidgeting and some help from THWACK, you can create your own charts, tables, dashboards, maps, and much more. Check out this post from THWACK MVP CourtesyIT, which has a master list of all the amazing ideas and customizations that have been posted in the community. Be sure to check out the section from THWACK MVP wluther:  he’s got some great content specifically tailored to dashboards. One thing to always keep in mind when using more advanced methods… SolarWinds support may not be able to assist you with the bending of spacetime. Fidget at your own risk!

In my opinion, one of the most powerful tools for creating custom resources is SWQL, the SolarWinds Query Language. With it, data is your slave. THWACK MVP mesverrum makes it easy in this post, where he provides an awesome example of how to create your own custom SWQL tables.

     Results

Let’s put all this together and create a shiny new dashboard that follows the idea of efficiency, information, and design. We need something that doesn’t waste space, contains useful data, and looks awesome. Something like this:

pastedImage_20.png

First thing’s first… we’re using the NOC view, indicated by the black bar at the top with the circles in the upper-right corner that represent the various sub-views in rotation. We have a map from Network Atlas (upper left), a PerfStack project added as a widget (lower left), AppStack (lower right), and a custom SWQL table that displays outage information (check out mesverrum​'s post about it here).

And there we have it! Five useful tools that you can use to make your dashboards amazing. Be sure to post your creations in the community. Here are some threads for NOC views and Network Atlas maps. Now go forth and dashboard!

Parents
  • It's not quite as dynamic as one might hope, but to make a dynamic link to a perfstack chart that changes based on the node you are viewing you can use a variation on the technique that wluther discussed in this post, Building Simple PerfStack Project Lists With SWQL

    For example, I use it with ${nodeid} as part of the below Custom Query widget to make it so that when you click on the CPU load it takes you to a dynamic perfstack with just cpu load and alert info on it.  Memory and latency and packet loss also each have their own charts when you click their links.

    pastedImage_1.png

    select distinct --n.caption as [Node], n.detailsurl as [_Linkfor_Node],

    isnull(alerts.[Active Alerts],0) as [Active Alerts]

    ,CASE

    when alerts.[active alerts] is null then '/Orion/images/ActiveAlerts/Check.png'

    WHEN sev.Severity = 4 THEN '/Orion/images/ActiveAlerts/Critical.png'

    WHEN sev.Severity = 3 THEN '/Orion/images/ActiveAlerts/Serious.png'

    WHEN sev.Severity = 2 THEN '/Orion/images/ActiveAlerts/Warning.png'

    WHEN sev.Severity = 0 THEN '/Orion/images/ActiveAlerts/InformationalAlert.png'

    WHEN sev.Severity = 1 THEN '/Orion/images/ActiveAlerts/Notice.png'

    END AS [_iconfor_Active Alerts]

    ,case when n.cpuload < 0 then 'Not Polled'

    when n.host.nodeid is not null and n.host.cpucorecount is not null then concat(round(n.host.cpuload,0),'% of ',n.host.CpuCoreCount,' CPU')

    when cpu.[cpu count] is not null then concat(cpuload,'% of ',cpu.[cpu count],' CPU')

    else 'Polling Error'

    end as [CPU Load]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.AvgLoad,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.MaxLoad,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts;' as [_linkfor_CPU Load]

    ,CASE

    WHEN cpuload >= htc.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN cpuload >= htc.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN cpuload < htc.Level1Value  THEN '/Orion/images/StatusIcons/Small-Up.gif'

    WHEN cpuload >= n.CpuLoadThreshold.Level2Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN cpuload >= n.CpuLoadThreshold.Level1Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN cpuload <  n.CpuLoadThreshold.Level1Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_CPU Load]

    ,case when percentmemoryused < 0 then 'Not Polled'

    else concat(percentmemoryused,'% of ',(round(n.totalmemory/1073741824,0)),' GB')

    end as [Memory Used]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.AvgPercentMemoryUsed,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.MaxMemoryUsed,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.TotalMemory,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts;' as [_linkfor_Memory Used]

    ,CASE

    WHEN percentmemoryused >= htm.Level2Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentmemoryused >= htm.Level1Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentmemoryused < htm.Level1Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Up.gif'

    WHEN percentmemoryused >= n.percentmemoryusedThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentmemoryused >= n.percentmemoryusedThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentmemoryused <  n.percentmemoryusedThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Memory Used]

    ,CASE

    WHEN responsetime<0 then 'No Response'

    ELSE concat(responsetime,' ms')

    END AS [Latency]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Status,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.MaxResponseTime,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.AvgResponseTime;' as [_linkfor_Latency]

    ,CASE

    WHEN responsetime >= n.responsetimeThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN responsetime >= n.responsetimeThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN responsetime <  n.responsetimeThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Latency]

    ,concat(percentloss,'%') as [Packet Loss]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.Availability,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Status,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.PercentLoss;' as [_linkfor_Packet Loss]

    ,CASE

    WHEN percentloss >= n.percentlossThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentloss >= n.percentlossThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentloss <  n.percentlossThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Packet Loss]

    --,n.percentmemoryusedThreshold.Level1Value

    from orion.nodes n

    left join (SELECT count(NodeID) as [CPU Count], nodeid

    FROM Orion.CPUMultiLoadCurrent

    group by nodeid) cpu on cpu.nodeid=n.nodeid

    left join Orion.VIM.HostThresholds htc on htc.host.NodeID=n.NodeID and htc.Name = 'VIM.Hosts.Stats.CPULoad'

    left join Orion.VIM.HostThresholds htm on htm.host.NodeID=n.NodeID and htm.Name = 'VIM.Hosts.Stats.MemUsage'

    left join (SELECT count(AlertActiveID) as [Active Alerts], aa.AlertObjects.RelatedNodeID

    FROM Orion.AlertActive aa

    group by aa.AlertObjects.RelatedNodeID) alerts on alerts.relatednodeid=n.nodeid

    left join (SELECT aa.AlertObjects.RelatedNodeID

    ,max(CASE

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 2 THEN 4

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 3 THEN 3

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 1 THEN 2

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 4 THEN 1

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 0 THEN 0

    END) AS [Severity]

    FROM Orion.AlertActive aa

    group by aa.AlertObjects.RelatedNodeID

    ) sev on sev.relatednodeid=n.nodeid

    where nodeid=${nodeid}

    order by n.cpuload

Comment
  • It's not quite as dynamic as one might hope, but to make a dynamic link to a perfstack chart that changes based on the node you are viewing you can use a variation on the technique that wluther discussed in this post, Building Simple PerfStack Project Lists With SWQL

    For example, I use it with ${nodeid} as part of the below Custom Query widget to make it so that when you click on the CPU load it takes you to a dynamic perfstack with just cpu load and alert info on it.  Memory and latency and packet loss also each have their own charts when you click their links.

    pastedImage_1.png

    select distinct --n.caption as [Node], n.detailsurl as [_Linkfor_Node],

    isnull(alerts.[Active Alerts],0) as [Active Alerts]

    ,CASE

    when alerts.[active alerts] is null then '/Orion/images/ActiveAlerts/Check.png'

    WHEN sev.Severity = 4 THEN '/Orion/images/ActiveAlerts/Critical.png'

    WHEN sev.Severity = 3 THEN '/Orion/images/ActiveAlerts/Serious.png'

    WHEN sev.Severity = 2 THEN '/Orion/images/ActiveAlerts/Warning.png'

    WHEN sev.Severity = 0 THEN '/Orion/images/ActiveAlerts/InformationalAlert.png'

    WHEN sev.Severity = 1 THEN '/Orion/images/ActiveAlerts/Notice.png'

    END AS [_iconfor_Active Alerts]

    ,case when n.cpuload < 0 then 'Not Polled'

    when n.host.nodeid is not null and n.host.cpucorecount is not null then concat(round(n.host.cpuload,0),'% of ',n.host.CpuCoreCount,' CPU')

    when cpu.[cpu count] is not null then concat(cpuload,'% of ',cpu.[cpu count],' CPU')

    else 'Polling Error'

    end as [CPU Load]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.AvgLoad,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.MaxLoad,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts;' as [_linkfor_CPU Load]

    ,CASE

    WHEN cpuload >= htc.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN cpuload >= htc.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN cpuload < htc.Level1Value  THEN '/Orion/images/StatusIcons/Small-Up.gif'

    WHEN cpuload >= n.CpuLoadThreshold.Level2Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN cpuload >= n.CpuLoadThreshold.Level1Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN cpuload <  n.CpuLoadThreshold.Level1Value and htc.Name is null THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_CPU Load]

    ,case when percentmemoryused < 0 then 'Not Polled'

    else concat(percentmemoryused,'% of ',(round(n.totalmemory/1073741824,0)),' GB')

    end as [Memory Used]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.AvgPercentMemoryUsed,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.MaxMemoryUsed,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.CPULoad.TotalMemory,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts;' as [_linkfor_Memory Used]

    ,CASE

    WHEN percentmemoryused >= htm.Level2Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentmemoryused >= htm.Level1Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentmemoryused < htm.Level1Value and htm.Name = 'VIM.Hosts.Stats.MemUsage' THEN '/Orion/images/StatusIcons/Small-Up.gif'

    WHEN percentmemoryused >= n.percentmemoryusedThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentmemoryused >= n.percentmemoryusedThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentmemoryused <  n.percentmemoryusedThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Memory Used]

    ,CASE

    WHEN responsetime<0 then 'No Response'

    ELSE concat(responsetime,' ms')

    END AS [Latency]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Status,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.MaxResponseTime,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.AvgResponseTime;' as [_linkfor_Latency]

    ,CASE

    WHEN responsetime >= n.responsetimeThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN responsetime >= n.responsetimeThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN responsetime <  n.responsetimeThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Latency]

    ,concat(percentloss,'%') as [Packet Loss]

    ,'/ui/perfstack/?presetTime=last7Days&charts=0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.Availability,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Status,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.PerfStack.Alerts,0_Orion.Nodes_'+tostring(nodeid)+'-Orion.ResponseTime.PercentLoss;' as [_linkfor_Packet Loss]

    ,CASE

    WHEN percentloss >= n.percentlossThreshold.Level2Value THEN '/Orion/images/StatusIcons/Small-Critical.gif'

    WHEN percentloss >= n.percentlossThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Warning.gif'

    WHEN percentloss <  n.percentlossThreshold.Level1Value THEN '/Orion/images/StatusIcons/Small-Up.gif'

    END AS [_IconFor_Packet Loss]

    --,n.percentmemoryusedThreshold.Level1Value

    from orion.nodes n

    left join (SELECT count(NodeID) as [CPU Count], nodeid

    FROM Orion.CPUMultiLoadCurrent

    group by nodeid) cpu on cpu.nodeid=n.nodeid

    left join Orion.VIM.HostThresholds htc on htc.host.NodeID=n.NodeID and htc.Name = 'VIM.Hosts.Stats.CPULoad'

    left join Orion.VIM.HostThresholds htm on htm.host.NodeID=n.NodeID and htm.Name = 'VIM.Hosts.Stats.MemUsage'

    left join (SELECT count(AlertActiveID) as [Active Alerts], aa.AlertObjects.RelatedNodeID

    FROM Orion.AlertActive aa

    group by aa.AlertObjects.RelatedNodeID) alerts on alerts.relatednodeid=n.nodeid

    left join (SELECT aa.AlertObjects.RelatedNodeID

    ,max(CASE

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 2 THEN 4

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 3 THEN 3

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 1 THEN 2

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 4 THEN 1

    WHEN aa.AlertObjects.AlertConfigurations.Severity = 0 THEN 0

    END) AS [Severity]

    FROM Orion.AlertActive aa

    group by aa.AlertObjects.RelatedNodeID

    ) sev on sev.relatednodeid=n.nodeid

    where nodeid=${nodeid}

    order by n.cpuload

Children
No Data
Thwack - Symbolize TM, R, and C