Tag: Grafana

  • Grafana variables – Easy step-by-step tutorial

    This is a very important and powerful feature in Grafana. Unfortunately, when one searches in Google the top hits tend to be Grafana official documentation, which more often than not is very formal. There are many people out there that learn by seeing examples. That’s the purpose of the tutorial, to show a clear step-by-step tutorial that is easy to understand and follow. I am running Grafana v7.5.15. I am going to include a good amount of screenshots to make it as easy to follow as possible. No doubt the interface will change in the future (that’s the nature of software) but hopefully it won’t have changed much by the time you read it.

    Variables allow you to update your dashboard dynamically by selecting interactively what you want to see. For example, I have a dashboard here that provides information about storage arrays in a datacenter, such as capacity and performance metrics. The datacenter in question has multiple storage arrays of different types. By default the panels in the dashboard show information about “all” of the arrays. But often, I would like to focus only on arrays of a certain type. The way of enabling this is to have a drop-down menu that allows me select the array type. When I select one type all the other arrays are hidden. As we will see the behavior is configurable and allows us to enable multiple selections.

    Grafana shows a separate drop-down for each variable you configure in your dashboard. You can have multiple drop-down menus. When you make a selection in any of them, the changes are applied to all panels in the dashboard.

    The way you obtain the labels for the drop-down menu varies. In our example we will use the “Query” type which means we perform a query to the data source to extract them. The actual syntax depends on the data source. Why? Grafana uses the query language native to the data source and as you know Grafana can work with a wide range of data sources: InfluxDB, Prometheus, MySQL … . In this post I am going to focus on Prometheus which seems to be one of the most prevalent out there nowadays.

    Everything starts by creating the variable. For this you need to open the “Dashboard settings” by click the “gear” symbol.

    Once in “Dashboard settings” click on “Variables”. Let’s click “New” to create our first variable.

    The “General” section has some very important fields. We are going to use “Query” type but you get other interesting possibilities. Two other important fields:

    • Name: This field needs to match what you use in the “query” field in the panel configuration
    • Label: This is what gets displayed in the drop-down menu for users to select

    Since we selected “Query” in the “General” section, we get a “Query Options” section. Here we need to select our data source and the query that will extract the labels that will be shown in the drop-down menu. As we mentioned, the query is written in a specific way to the data source type. For example, for a MySQL query type we would need to write an actual SQL query, but for Prometheus we use “PromQL”, ie Prometheus Query Language. In the screenshot above you can see I am using “label_values(name)”. This query will retrieve all the labels that were defined for the metric. So it is very important that what you put here matches exactly the labels you used. For example, the following is the code in my exporter:

    STORAGE_FREE_PERCENT = Gauge('storage_free_percent','Percentage of free storage',['name','system_type'])

    Notice how ‘name’ is one of the two labels defined for the metric. There could be multiple ones, hence they are a “list” enclosed by square brackets.

    I you enable “sort”, the labels in the drop-down menu will be sorted alphabetically. Selecting “multi-value” will allow you to select multiple labels at the same time. The “Include All option” will also show an “All” label that selects all labels. If all goes well, at the bottom of the “Edit” page you can see a “preview of values”. It helps you see if your query is working.

    Once you are finished configuring the variable, click “Update”. This brings you back to the “Variables” top level menu. You will see a green mark if the variable is correctly being referenced by your dashboard or by other variables. In the screenshot below you can see I have created a variable “system_type” and another one for “name”

    Before we move on to the final step let’s see graphically how the settings.

    As you can see the final step is to build a query in your panel that includes the name of the metric and the reference to your variables in between curly brackets. The variable itself needs to be prepended with the “$” symbol.

  • Grafana “invalid query: unexpected character”

    While working on a dashboard in Grafana I came across an error that puzzled me for a while. So I am writing this in the hope that it will help other people who value their time 🙂

    My setup is quite straight forward:

    • Prometheus v2.46.0
    • Grafana v7.5.15

    However, don’t get too hung up on the versions because I have seen other people complaining about the same behavior with other versions. The key is that the problem might lie with the browser. For completeness, I am using Google Chrome v116.0.5845.141.

    The symptoms are:

    • I edit a new panel in a dashboard and I start typing the Prometheus query in the “Metrics” box. When I put a metric only nothing bad happens, but as soon as I add a “curly bracket” ie “{” the Metrics box gets a life of its own. It starts duplicating letters and the cursors don’t seem to be responding. When using the cursors it feels like I need to use the cursor 3 times to advance a single character.
    • The panel gets a red exclamation box in the top-left corner. If I hover over the exclamation the following message pops up “invalid parameter \”query\”: 1:21: parse error: unexpected character: ‘\\ufeff’”

    This is what it looks like in my case

    Everything points to some strange characters being inserted

    If it is true that the problem is the browser, you might have to use a different browser. But as a workaround what I figured is that you can edit the Metric query in the panel’s JSON source directly.

    You can get there by either:

    • click on the “red exclamation” and then the “JSON” tab
    • Or click on the panel’s name drop-down arrow, then “Inspect” and then “JSON”

    At this point if you scroll down to “targets” you can see the “expr” field with all the garbage around it

    Now you can click on the “expr” line and edit the query cleanly without introducing those weird characters.

    IMPORTANT: One thing to watch out for is that you need to escape the double quotes in your query with a backslash. Otherwise they will get confused with the JSON’s own double quotes. This is what it looks like in my example:

    storage_free_percent{system_type=~\"$system_type\",name=~\"$name\"}

    I hope it helps!

  • Create a health score in Grafana

    This is part 2 of a small series we started to show some techniques that allow us to build a hierarchy of dashboards with Grafana. In the first part we learnt how to create links both at the panel and at the dashboard level. In this article we are going to explore how to create health status metrics that we can use in our “Top” level dashboard to get an at-a-glance view of a single system. Our dashboard will likely have one of these for every system being managed

    Producing a health metric is going to require some basic math. The question is “where” do we do these calculations. Even though the calculations are not necessarily complicated the general guidance is not to do them in Grafana. What we are going to show here is how to calculate the health score as we take the measurement. Then we will store the health data along with the sensor data into the time series database as it is produced. If you want to do this in Grafana you might want to explore the “Expressions” functionality, but at a time of writing is a beta feature and you get warned that it might not be there in future versions.

    I will provide some sample scripts in Python. If you don’t use Python in your environment, it doesn’t matter as the main thing now is to focus on the actual logic. In order to work with sample data we are going to create some random numbers for 3 different metrics representing the environment conditions of a certain location (a warehouse, a lab …). These metrics will be fake temperature, humidity and noise readings but you could use different metrics for your use case. Also not that the time series database we are using is InfluxDB, which is very popular these days.

    When we calculate a health metric that summarizes all these readings we have 2 options.

    • Combine all metrics into one
    • Use the health of the worse metric

    Combine all metrics into one

    In this method we start with the maximum health value and then discount health points as you parse the data to find out the current health. Note how I have used 10 as the top health score. Other use cases might benefit from using 100 as the top score in which case you can interpret the health number as a percentage

    import time
    import random
    from influxdb import InfluxDBClient
    inf_db = "iot_database"
    client = InfluxDBClient(host='localhost', port=8086)
    client.switch_database(inf_db)
    
    for x in range(10000):
        i = random.randint(20,45) # temperature reading
        j = random.randint(40,80) # humidity reading
        k = random.randint(40,60) # noise reading
    
        # Let's calculate the health based on the current readings
        health = 10 # Start with max possible health and substract from there
        if i > 30: health -= 1
        if i > 40: health -= 2
        if j > 60: health -= 1
        if j > 70: health -= 1
        if k > 50: health -= 1
    
        data = 'lab Temperature={},Humidity={},Noise={},Health={}'.format(i,j,k,health)
        print str(x).zfill(4) + " : " + data
        client.write([data],{'db':inf_db},204,'line')
    
        time.sleep(5)
    

    Notice how I am taking health points if temperature is high and then take extra points if it is even higher. In my opinion this produces simpler code than doing double conditions such as “if i < 40 and i < 30”

    We can add more penalty to metrics or conditions that are more severe. For example notice how temperatures over 40 take 2 extra points instead of 1.

    If you have many metrics contributing to health and all of them are taking many points away you might end up with negative numbers. You might add another line of code that turns health to 0 if the calculated value is a negative number

    We run the code and we get the following output. As we are using random numbers we get metrics swinging very wildly but it is a good thing in this case because we can see how the health parameter is reacting

    The “Health” metric is numerical so if we want to use a “stat” panel with status such as “OK” or “CRITICAL” we will need to use “Value Mapping” in Grafana. First let’s create a panel in the “Top” level dashboard. Make sure is of the type “stat”. You can configure the “query” as follows. Notice the “FORMAT AS Table”:

    Then go to the “settings” in the right-pane and scroll-down to “Value mappings”. You can configure your value mappings as follows. Don’t forget to set the “Display text” and the “Color”

    We can then get out of panel editing mode and observe how our “stat” panel behaves. Notice how I have added a link to another dashboard that shows the actual time series for all the variables as described in the previous post.

    Since we are representing “Health” by a number, another way of presenting it in our “Top” level dashboard is with a “Gauge” panel. These types of panels are also very visual as they show you the current value in relation with the minimum and maximum values in the range. Let’s add a new “Gauge” panel and configure the query as follows, notice how we are now using “FORMAT AS Time series”

    For a “Gauge” it is important to define the range of possible values. In our case this is 0 and 10 as shown below. If you have defined your health metric as a percentage you can set the range from 0 to 100 and select “Percent(0-100)” in the “Unit” field

    If we get out of edit mode the changes are made right away and our new “Gauge” panel looks like this

    You can also use value mapping to show a health label instead of the health number, which along with the color conveys a very clear message. In the screenshots below I am using the same “Value mappings” we used for the “Stat” panel above

    Use the health of the worse metric

    Another way of calculating a metric would be to pick up the status of the worst metric. This approach is more conservative and it has its merits. The first thing we need to do is to calculate a different health score for each metric and then select the worst one as the overall health of the whole system. You can see some sample Python code below to illustrate the concept

    import time
    import random
    from influxdb import InfluxDBClient
    inf_db = "iot_database"
    client = InfluxDBClient(host='localhost', port=8086)
    client.switch_database(inf_db)
    
    for x in range(10000):
        i = random.randint(20,45) # temperature reading
        j = random.randint(40,80) # humidity reading
        k = random.randint(40,60) # noise reading
    
        # Let's calculate the health based on the current readings
        temp_health  = 10
        humi_health  = 10
        noise_health = 10
    
        if i > 40: temp_health -= 2
        if i > 30: temp_health -= 1
        if j > 70: humi_health -= 1
        if j > 60: humi_health -= 1
        if k > 50: noise_health -= 1
    
        # Now let's pick the metric with the smallest value
        health = min(temp_health, humi_health, noise_health)
    
        data = 'lab Temperature={},Humidity={},Noise={},Health={}'.format(i,j,k,health)
        print str(x).zfill(4) + " : " + data
        client.write([data],{'db':inf_db},204,'line')
    
        time.sleep(5)
    

    As before you could put more weight on a given metric if a bad situation on that subsystem tends to produce more critical situations. In our example you can see how we are discounting more health points in Temperature than the other 2 metrics

    This is a sample output of the script

    Notice how the last 2 intervals produce the same overall health status of 9 based on very different conditions. In interval “0006” the Temperature threshold was exceeded. Whereas in “0007” it was the humidity threshold that determined the “Health” value.

    I hope it helps!

  • Grafana dashboard Hierarchy

    It took a while to decide the title of this post but I am still unsure whether it conveys the purpose of the post. The point is that we all start our Grafana journey by creating some cool graphs in a dashboard, but after a while we typically end up with many many dashboards … so eventually we start looking for an at-a-glance view that summarizes all our dashboards. Think of one of those dashboards that use at the operations centers

    We are going to explore some techniques that enable you to build such a hierarchy in Grafana:

    The objective is to have a top level dashboard that summarizes all the others. We also need a way of bringing up those other second level dashboards if we want more detail about a specific system. In this section we will see how to create links in Grafana.

    In my environment I have 2 dashboards:

    • Top. This is my pretend top level dashboard that will contain the at-a-glance view of all my monitored systems. This dashboard is likely to contain “Stat” panels (and maybe gauges) showing the overall status of multiple systems
    • Second. This is a dashboard that contains details about a specific system and as such is likely to contain time series, chart panels and other sophisticated visualizations

    In Grafana you can create links at the panel level and the dashboard level

    The main idea here is that if I click on one of the stat panels it will take me to the second level dashboard where I can see all the details. Maybe the stat panel is showing a red colored “CRITICAL” message and by clicking on it I can go to the second level and see what subsystem is causing the issue.

    In my “Top” level dashboard I have currently a single Stat panel that shows us the health of a certain location, a “warehouse” in this case. There will be some metrics that we aggregate to produce this “health”. In the next article we will explore how to do that. For now this is how it looks:

    Dashboards in Grafana are displayed in a browser by using their URL. This includes a unique ID as well as the actual name as you can see in the following screenshot. You will need to record the URL of the “second” level dashboard so go ahead, open the “second” level dashboard and record its URL.

    Once you have the URL you can go to the Top level dashboard and define a link on the “Warehouse” health stat panel. Then go to the Options section in the right pane and select “Panel links” and then “Add link”

    Here you can add a title for your link and the URL of the second level dashboard we save in the previous step. Optionally you can choose to open the second dashboard in a new tab. Click “Save” and get out of Edit mode

    Now, in the “Top” level dashboard you can see a little arrow icon on the top-left corner of the Stat panel. If you hover your mouse over it you will see the title of the link you provided. And when you click on it it will open the second level dashboard

    The other alternative is to create dashboard links. These will permanently display at the top-right corner of your dashboard.

    Let’s go ahead and create 2 dashboard links:

    • Link to other dashboards
    • Link to an external site

    Start by opening the dashboard settings. You will find the icon at the top-right corner of the dashboard

    Then click on “Links” on the left and then “New Link”. Let’s create a link called “Dashboards”. The “Title” is the string that will be clickable. For “Type” we select “Dashboards”. If you only have a handful of dashboards they will all display in the same line. However if you are planning to have many, it’s better to tick the “Show as dropdown” checkbox to things neater.

    Considering this “Top” level dashboard is likely to show in an operations center, another use case would be to have handy some links related to support, such as an internal ticketing system, a vendor support site or a list of emergency contacts. Now let’s go ahead and create another link that links to the support page of a vendor so that we can open a service request. This time we will select the “Link” type and provide the URL to open when clicked. You can customize the link by selecting an “icon” that is meaningful for your use case. Notice how I have also force it to open the linked page in a “new tab” as we want our dashboard to remain open after we are done with the service request

    This is what the “Links” menu in dashboard “Settings” looks like with both links configured

    Finally “Save Dashboard” and once in the dashboard you should see something like this. Notice how I have clicked in the “Dashboards” button and the existing dashboards (which is only “second” in this case) are shown

    In the next article we will focus on how to create aggregate multiple metrics into a overall health number.

  • Grafana Stat panel with a String

    Grafana has become a very popular tool for monitoring systems and applications partly due to the amount of features and integrations it provides. The graphs it produces are beautiful. However sometimes you need to show a string or a value instead of a full graph. For that purpose Grafana provides the “Stat” panels. These are very often used to show a single value, such as the last reading or the moving average of a given metric.

    However sometimes you want to display a string. An example of this could be a “health” status, such as OK or CRITICAL

    or it could be some some other message you are collecting such as this

    We are going to show how to handle this scenario but for completeness let’s use some Python code. In this example we will be collecting some environment data and storing it into InfluxDB. On every interval we are going to:

    • read 2 numerical values (Temperature and Humidity)
    • infer a “Health” text value by comparing the 2 previous values against some threshold
    • write all 3 values to the database

    The code requires you to install the “influxdb” Python library. You can do so with “pip install influxdb”

    # Import the Influx client from the Python library
    from influxdb import InfluxDBClient
    
    # Create a connection to InfluxDB
    client = InfluxDBClient(host='localhost', port=8086)
    
    # Connect to the right database
    inf_db = "iot_database"
    client.switch_database(inf_db)
    
    while True:
        # Read the data from your sensors or a REST API ...
        # Let's say we got:
        temp = 25
        hum  = 60
    
        # Depending on some predefined thresholds we could derive the Health
        if temp < 35 and hum < 80:
            h = "OK"
        else:
            h = "CRITICAL"
    
        # Then we write the data
        data = 'warehouse Temperature={},Humidity={},Health={}'.format(temp,hum,h)
        client.write([data],{'db':inf_db},204,'line')
    
        # Pause for 5 seconds until the next iteration
        time.sleep(5)

    Now let’s see how we can use the “Health” text value in Grafana. Add a “Stat” panel to your dashboard and on the query section you need to “format as table” and select the “last” value.

    At this point the panel will still display “No data”. So you need to go to the “Options” section on the right pane and scroll down to “Fields”. By default, “Numeric Fields” will be selected, but you need to select “last”

    Additionally you might want to set “Graph mode” to “None”. By default Stat panels will want to show a graph as well as the value but in this case there is no graph anyway because the “Health” field is not numerical.

    Finally you might want to apply a color code to the text in your “Stat”. Unfortunately threshold-based coloring won’t work because Health contains not numerical values. Don’t despair, we can still color them to our liking by using “Value mappings”. You will find this option at the very bottom of the “Options” pane.

    You can add a “new value mapping” for each type of health status your code is producing, ex: OK, CRITICAL … Specify the value to match on the left and the color on the right as shown above

    In our simple code we had only 2 different health status hence our resulting value mappings is as follows

    So now when the sensor data is above the threshold we write Health = CRITICAL and it displays as follows:

    In a future post I will share some tips to build a hierarchy of dashboards including a front dashboard to be used in your control center with a visual snapshot of your entire operation