avatarIvan Polovyi

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9547

Abstract

pan>}</pre></div><figure id="930c"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*GCqXJ0-1ZtPR0OIeQz3B1A.png"><figcaption></figcaption></figure><p id="0830">We can select metrics by multiple labels separated by the coma. Consider such a query as a query with an AND operator:</p><div id="a5b5"><pre>prometheus_http_requests_total{handler!=<span class="hljs-string">"/metrics"</span>}</pre></div><figure id="39cf"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*YqfZcYEzgnzXjV68E4q7lQ.png"><figcaption></figcaption></figure><p id="81f5">A very useful operator is a regex operator, it allows to create of flexible queries like the below:</p><div id="86a9"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics|/graph"</span>}</pre></div><figure id="75c6"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*2PwyFajTybzYegs11_q1XA.png"><figcaption></figcaption></figure><p id="197b">This query uses a pipe (|), and it behaves as an OR operator.</p><p id="0a53">The wild card can be used in regex expressions like so:</p><div id="03f6"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">".v1."</span>}</pre></div><p id="6a35">This query selects metrics containing “v1” inside the label handler. The wild card “.*” can be applied in front and at the back of the value or both.</p><p id="6aae">All the above queries apply to range vectors, the only additional thing we have to add is duration, which goes into square brackets. In brackets, we specify a number followed by the time unit.</p><div id="ec6b"><pre> | Unit | Meaning | | -------- | --------------| | ms | milliseconds | | s | seconds | | m | minutes | | h | hours | | d | days (24h) | | w | weeks (7d) | | y | years (365d) |</pre></div><figure id="320a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Ow48Qepdwz8ErDdWvpUODw.png"><figcaption></figcaption></figure><p id="84de">Time units can be combined like so:</p><div id="4d22"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics"</span>} [1m30s]</pre></div><figure id="011f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*JG9slDt5--aSsanVDkNhaQ.png"><figcaption></figcaption></figure><h2 id="263d">Offset modifier</h2><p id="df21">The offset modifier is used to shift the time offset for individual instant and range vectors in a query.</p><div id="5c30"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics"</span>} offset 10m</pre></div><p id="5899">This query returns a sample that was taken 10 minutes in the past relative to the current time.</p><figure id="53a0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*aF6-KNKMIxQBlRt-X0S79g.png"><figcaption></figcaption></figure><p id="0d93">The query returned a result that was collected 10 minutes ago. To better understand how it works below I executed a query that returned a range vector with a range of 11 minutes. When we get the timestamp and convert it to date time it will be a date and time exactly 10 min ago.</p><p id="96cc">In the same way, the offset can be applied to a range vector:</p><div id="f002"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics"</span>}[1m] offset 10m</pre></div><figure id="5516"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*9bmZtHPw9ErF9QIlzwfW8Q.png"><figcaption></figcaption></figure><h2 id="8bd8">Binary arithmetic operators</h2><p id="d04c">The following binary operators can be applied in PromQL with scalar and instant vectors</p><div id="1b7d"><pre> | Operator | Meaning | | -------- | --------------| | + | addition | | - | substraction | | * | multiplication| | / | division | | % | modulo | | ^ | power |</pre></div><p id="594f">Used with scalar values it will result in a scalar value.</p><figure id="8d03"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*3OT2_9NxluRLK_49fuQWYg.png"><figcaption></figcaption></figure><p id="f1e0">When applied with a scalar value and instant vector the scalar value is applied to each element of an instant vector</p><div id="d1bb"><pre>prometheus_http_requests_total{handler=~<span class="hljs-string">".v1."</span>}+1</pre></div><figure id="7776"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*_9GRqLn-nbY_xrCpCh1MVg.png"><figcaption></figcaption></figure><p id="7f29">When we apply a binary operator with instant vectors the result is going to be a new vector containing elements that are present in both vectors.</p><figure id="e707"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*YIstRSDhqs6eDuic6Iz9uw.png"><figcaption></figcaption></figure><figure id="d224"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Fcxx7AVXgo4_DeA1BjgvJw.png"><figcaption></figcaption></figure><h2 id="2d43">Comparison operators</h2><p id="8eb3">The following comparison operators can be applied</p><div id="24e5"><pre> | Operator | Meaning | | -------- | --------------------| | == | equals | | != | not equals | | > | grater-than | | <= | less-than | | >= | grater-than or equal| | <= | less-than or equal |</pre></div><p id="eaac">Applied to the scalar value will give a boolean value (0-false, 1-true). When using those operators with scalars we have to add a special “bool” modifier.</p><figure id="bca9"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*qCoHDX_ueOXFjNTZhX7NKA.png"><figcaption></figcaption></figure><p id="4bf6">When the operator is used with scalar and instant vectors the result of the query will be a new vector with only values that are matching to the applied operator.</p><div id="ab9c"><pre>prometheus_http_requests_total==7</pre></div><figure id="e841"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*9P7lDFCFGAwI41fFTRE1Vg.png"><figcaption></figcaption></figure><p id="fbf4">When we apply a comparison operator with instant vectors the result is going to be a new vector containing elements that are present in both vectors.</p><figure id="82a8"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*aUQ6sdl9Cn4JGlgbFIJwxw.png"><figcaption></figcaption></figure><h2 id="53ab">Set binary operators</h2><p id="83ea">Can only be applied to Instant Vectors:</p><div id="eedc"><pre>| Operator| Meaning | | --------| ------------------------------------------------------------------| | and | new vector with element that matches <span class="hljs-keyword">in</span> both | | or | new vector <span class="hljs-built_in">which</span> is the union of all unique elements | | unless | new vector <span class="hljs-built_in">which</span> elements <span class="hljs-built_in">which</span> are not present on the left side |</pre></div><p id="5f16">When running the following query no result will be found, because there are no matching elements in both vectors</p><figure id="e18f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*rMZRYgV0A1ErXRrzTKmWIg.png"><figcaption></figcaption></figure><div id="8bcc"><pre>prometheus_http_requests_total{handler=<span class="hljs-string">"/api/v1/query"</span>} AND prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics"</span>}</pre></div><p id="a60d">When using the OR operator the result will be as follow</p><figure id="af8a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*ovn5Rfg_xk_dW69TUjHAGA.png"><figcaption></figcaption></figure><p id="22a0">This query returns all elements present in both vectors. And the query with the Unless operator returns elements from the left side vector that are not present in the right side vector.</p><figure id="e1b5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*psgswbotkWbfq0Ey2fz77Q.png"><figcaption></figcaption></figure><h2 id="26d7">Aggregation operators</h2><p id="382f">Prometheus has a wide variety o aggregation operators that can be applied to instant vectors. The <i>sum</i> aggregator calculates the sum of all elements in the vector.</p><div id="7fde"><pre><span class="hljs-built_in">sum</span>(prometheus_http_requests_total)</pre></div><figure id="2daf"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*YZwo0rSOBe2GaS3bNHsJjw.png"><figcaption></figcaption></figure><p id="ecec"><i>Min</i> and <i>max</i> aggregators calculate the lowest and highest value in the vector:</p><div id="9731"><pre>min(prometheus_http_requests_total)</pre></div><figure id="1990"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*IdzpJYKazox8jnKTIdtVmg.png"><figcaption></figcaption></figure><div id="c11a"><pre>max(prometheus_http_requests_total)</pre></div><figure id="e801"><img src="https:

Options

//cdn-images-1.readmedium.com/v2/resize:fit:800/1*JAAz1bAW2rTYX9kQUe5RHg.png"><figcaption></figcaption></figure><p id="c71f">The <i>avg</i> calculates the average of the vector:</p><div id="5295"><pre>avg(prometheus_http_requests_total)</pre></div><figure id="f232"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*D_jYsvEc2KgXYT0-CnzlJQ.png"><figcaption></figcaption></figure><p id="4d11">The <i>count</i> aggregator returns the number of elements in the vector</p><div id="f751"><pre>count(prometheus_http_requests_total)</pre></div><figure id="76c0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*cFr6kNDbsR0zuPx1wQZWZQ.png"><figcaption></figcaption></figure><p id="f014">The aggregator <i>count_values</i> counts a number of elements in the vector with the same value.</p><div id="1d12"><pre>count_values (<span class="hljs-string">"prometheus_http_requests_total"</span>, prometheus_http_requests_total)</pre></div><figure id="6f1e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*eqwVXL3SwVTEfWfqo0hctA.png"><figcaption></figcaption></figure><p id="64f8">The aggregator <i>tork</i> returns n largest values from the vector:</p><div id="52af"><pre>topk(2,prometheus_http_requests_total)</pre></div><figure id="ca21"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*yWba27YbvprHTGXfKrHFTw.png"><figcaption></figcaption></figure><p id="9bb9">And the <i>bottomk</i> works in the opposite way</p><div id="7095"><pre>bottomk(2,prometheus_http_requests_total)</pre></div><figure id="3d68"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*81aN3znBdDlHg-4QQmA1Ow.png"><figcaption></figcaption></figure><p id="5d3f">The operator <i>group</i> does what its name says groups elements and returns 1</p><div id="dfca"><pre>group(prometheus_http_requests_total)</pre></div><figure id="bff2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*hudVJrbyJ66kEGNwU-YPGg.png"><figcaption></figcaption></figure><p id="a4d8">We can aggregate a vector by specific labels, like so by appending a “by” modifier.</p><div id="d0ba"><pre><span class="hljs-built_in">sum</span>(prometheus_http_requests_total) by (code)</pre></div><figure id="2712"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*CKFJWbtEF_TZweDq6ut6Pg.png"><figcaption></figcaption></figure><p id="572c">If we want to exclude some labels we can add a special modifier “without”:</p><div id="b835"><pre><span class="hljs-built_in">sum</span>(prometheus_http_requests_total) without (code)</pre></div><figure id="f23d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*JDftezaeHhTpBbaw4e5LXA.png"><figcaption></figcaption></figure><p id="4d6e">We can use aggregators over time for range vectors such as</p><div id="b85f"><pre>avg_over_time(prometheus_http_requests_total[10s])</pre></div><figure id="07d7"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*GboZTYRzhZuWjifzNo3uHA.png"><figcaption></figcaption></figure><p id="9623">This aggregator calculates the average in the vector in a specified range.</p><p id="e9e8">Prometheus has plenty of aggregators that can be applied to range vectors. They are <i>sum_over_time</i>, <i>min_over_time</i>, <i>max_over_time</i>, <i>count_over_time</i>, and many more.</p><figure id="bd09"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Xyo_pPVleFhoO4s0p_Bayg.png"><figcaption></figcaption></figure><h2 id="21e5">Functions</h2><p id="2cce">Prometheus offers us a wide variety of functions. The first function that we going to check is <i>absent</i>. This function checks if an instant vector has any elements. Returns an empty vector when a vector passed to this function contains elements and returns 1 when a vector doesn't have values.</p><div id="2d0c"><pre>absent(prometheus_http_requests_total)</pre></div><figure id="b025"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*4zUxvd8RS285QBYdvaE6Sw.png"><figcaption></figcaption></figure><p id="0602">If we need to get the same result but for a range vector, we have to use the following function:</p><figure id="225d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*lLdWbYwEj2TT-lw3otNVkQ.png"><figcaption></figcaption></figure><p id="39b8">Prometheus has mathematic functions such as <i>abs</i>, <i>ceil</i>, and <i>floor</i>.</p><p id="2608">The function <i>clamp</i> converts the lowest values to the value specified as a second parameter and converts the largest values specified as a third parameter.</p><div id="33e8"><pre>clamp(prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics|/api/v1/labels|/api/v1/format_query"</span>},3,6000)</pre></div><figure id="8dca"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*56NrUKLeCueTaq5tqe6oWg.png"><figcaption></figcaption></figure><p id="599f">From the screen, we can see that this function converted the highest sample from 6162 to 6000 and the lowest from 2 to 3.</p><p id="8cfe">There are 2 more versions of this function <i>clamp_min</i> and <i>clamp_max</i></p><div id="d2ef"><pre>clamp_min(prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics|/api/v1/labels|/api/v1/format_query"</span>},3)</pre></div><div id="1b58"><pre>clamp_max(prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics|/api/v1/labels|/api/v1/format_query"</span>},6000)</pre></div><figure id="bfaf"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*RnokkBf3OmqVEr49gU00VA.png"><figcaption></figcaption></figure><p id="6cfa">Those functions will make graphics look a bit nicer, by removing extreme spikes.</p><p id="50f3">Prometheus has a set of functions to work with date and time, such as <i>day_of_month, day_of_week, </i>and more.</p><p id="9dc3">Day of month returns the day of the month (1–31) for every timestamp in a UTC format. And the day of the week returns the day of the week (1–7) for every timestamp in UTC format.</p><figure id="0061"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fWEh3kkTa7okGNzQLSrm8Q.png"><figcaption></figcaption></figure><p id="7f32">The <i>time</i> function returns near the current timestamp</p><figure id="3353"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*SEY-c-n1eA9QWTa9H7LbOQ.png"><figcaption></figcaption></figure><p id="f451">The function <i>timestamp</i> returns the timestamp on which each element of a vector was sampled.</p><div id="9207"><pre>timestamp(prometheus_http_requests_total)</pre></div><figure id="98bd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*vi4_z2lQivEcEzlQb3ofGQ.png"><figcaption></figcaption></figure><p id="def9">If we need to sort the instant vector we can use sort and sort_desc functions. First sorts the vector in ascending order and the second in descending order.</p><div id="ec50"><pre><span class="hljs-built_in">sort</span>(prometheus_http_requests_total{handler=<span class="hljs-string">"/metrics|/api/v1/labels|/api/v1/format_query"</span>})</pre></div><div id="d9fb"><pre>sort_desc(prometheus_http_requests_total{handler=~<span class="hljs-string">"/metrics|/api/v1/labels|/api/v1/format_query"</span>})</pre></div><figure id="71fd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*YCpbDNhR4z2mXvCAqXpt0w.png"><figcaption></figcaption></figure><p id="c288">The complete project can be found here:</p><div id="1019" class="link-block"> <a href="https://github.com/polovyivan/prometheus-query-language"> <div> <div> <h2>GitHub - polovyivan/prometheus-query-language</h2> <div><h3>Contribute to polovyivan/prometheus-query-language development by creating an account on GitHub.</h3></div> <div><p>github.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*VBalhKbwbjVQCbJV)"></div> </div> </div> </a> </div><h2 id="eb7a">Conclusion</h2><p id="9545">This tutorial is about PromQL, a tool that can help you extract important information from the metric of your system. It also helps to create a visualization of metrics and define alarms that will alert you about a problem in your system.</p><p id="57a0">Thank you for reading! Please like and follow. If you have any questions or suggestions, please feel free to write in the comments section or on my LinkedIn <a href="https://www.linkedin.com/in/ivan-polovyi-5a4082178/">account</a>.</p><p id="f661">Become a <a href="https://polovyiivan.medium.com/membership">member</a> for full access to Medium content.</p><h1 id="7c55">Level Up Coding</h1><p id="67b0">Thanks for being a part of our community! Before you go:</p><ul><li>👏 Clap for the story and follow the author 👉</li><li>📰 View more content in the <a href="https://levelup.gitconnected.com/?utm_source=pub&amp;utm_medium=post">Level Up Coding publication</a></li><li>💰 Free coding interview course ⇒ <a href="https://skilled.dev/?utm_source=luc&amp;utm_medium=article">View Course</a></li><li>🔔 Follow us: <a href="https://twitter.com/gitconnected">Twitter</a> | <a href="https://www.linkedin.com/company/gitconnected">LinkedIn</a> | <a href="https://newsletter.levelup.dev">Newsletter</a></li></ul><p id="3f7b">🚀👉 <a href="https://jobs.levelup.dev/talent/welcome?referral=true"><b>Join the Level Up talent collective and find an amazing job</b></a></p></article></body>

Introduction to Prometheus PromQL. Local setup included

Prometheus is a powerful tool used for collecting metrics from a variety of devices. PromQL is a query language used to fetch necessary data used to analyze and for a graphical representation using tools such as Grafana.

Data

Prometheus stores data as a time series. Each entry in Prometheus consists of a metric name, a set of labels, a UNIX timestamp, and a sample collected at that timestamp.

In the example above, we have a metric that reflects the total of HTTP requests performed to a particular endpoint and is called:

prometheus_http_requests_total

This metric has a list of labels, one indicates an HTTP response code, and another the endpoint (handler). The time stamp indicates that this metric was sampled every 30 seconds.

Metrics type

Now we have to understand how Prometheus collects the data. From the Prometheus server perspective, there are no different types of metrics and the server used all data as untyped time series. At least at the moment, remember that this can change in the feature.

The differentiation exists only in client libraries used to gather metrics. So the client libraries have 4 types of metrics.

Counters as the name suggests it is used to count some events. This type should be used for a metric that only goes up or can be reset to a zero value. For example, request counts of some endpoint, messages sent to a queue or topic, etc.

A gauge is similar to a counter, as it is a single numeric value but it can go up and down. This type is used to represent the usage of computer resources, for example, the percentage of memory, or percentage of CPU used at any given time. It can be used to represent a number of container instances or a number of threads at a particular timeframe. In this case, it can go up and down.

Histogram sample observations usually duration of some event, such as HTTP request and response. It samples them by their frequency or count, putting the gathered values in pre-defined buckets. The Prometheus client library uses a set of default buckets (e.g. for the Go client library, it uses .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10). If custom values for buckets are required it can be overridden. Buckets are used to track the distribution of an attribute over a number of events.

A histogram samples observations (usually things like request durations or response sizes) and counts them in configurable buckets. It also provides a sum of all observed values.

The summary works similarly to the histogram, but on top, it provides some additional parameters. Such as a total count of observations and a sum of all observed values. And it calculates configurable quantiles over a sliding time window.

PromQL data types

Prometheus Query Language (PromQL) is a query language used to select and aggregate data stored in Prometheus, in real-time.

When querying data by PromQL the Prometheus will represent data in 4 different formats: String, Scalar, Instant, and Range vectors.

The String type represents text and is currently unused. The Scalar type represents numerical values.

The vector in Prometheu's perspective is a set of related time series. And you remember that Prometheus stores all its data as a time series.

The instant vector represents a set of time series where every timestamp maps to a single data point at that “instant”.

The range vector doesn’t represent only one value, like the instant vector, it represents a set of values measured between two timestamps. The square brackets are used to specify a time range (duration).

Run Prometheus locally

The easiest way to learn how PromQL works is to create a Prometheus instance on the local machine using Docker and Docker Compose.

The docker-compose file is below:

version: "3.8"

services:
  prometheus:
    container_name: prometheus
    image: prom/prometheus:v2.44.0
    user: root
    volumes:
      - ./prometheus:/etc/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus-config.yaml
      - --log.level=debug
    ports:
      - "9090:9090"
    networks:
      - prometheus-network

networks:
 prometheus-network:

This file defines one container based on the Prometheus Docker image with version 2.44. This container has one volume mapped that contains a Prometheus configuration file. The configuration file is below:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    scrape_interval: 5s
    static_configs:
      - targets: ['localhost:9090']

This file defines the scrape config. Based on it Prometheus will collect its own metrics. Using these metrics we can perform a variety of queries.

To create a container run the following command from the directory where the docker-compose file is located:

docker compose up

Now the Prometheus UI can be accessed using the browser on the address:

http://localhost:9090

Timeseries selectors

To select a specific instant vector the easiest way is to type its name in the prompt:

As you can see this query returned more than one result. To select the required information we can use label selectors. These selectors go in curly braces appended after the name of the metric.

prometheus_http_requests_total{l1=v1,ln=vn}

For example, if the requirement is to select a metric with the label “handler” equal to “/metrics” we use the following syntax:

prometheus_http_requests_total{handler="/metrics"}

The following operators can be applied to label selectors:

                   | Operator | Meaning              |
                   | -------- | -------------------- |
                   | =        | equals               |
                   | !=       | not equals           |
                   | =~       | regex matches        |
                   | !~       | regex does not match |

When we need to select all metrics but one collected from the metrics handler we use the following query:

prometheus_http_requests_total{handler!="/metrics"}

We can select metrics by multiple labels separated by the coma. Consider such a query as a query with an AND operator:

prometheus_http_requests_total{handler!="/metrics"}

A very useful operator is a regex operator, it allows to create of flexible queries like the below:

prometheus_http_requests_total{handler=~"/metrics|/graph"}

This query uses a pipe (|), and it behaves as an OR operator.

The wild card can be used in regex expressions like so:

prometheus_http_requests_total{handler=~".*v1.*"}

This query selects metrics containing “v1” inside the label handler. The wild card “.*” can be applied in front and at the back of the value or both.

All the above queries apply to range vectors, the only additional thing we have to add is duration, which goes into square brackets. In brackets, we specify a number followed by the time unit.

                   | Unit     | Meaning       |
                   | -------- | --------------|
                   | ms       | milliseconds  |
                   | s        | seconds       |
                   | m        | minutes       |
                   | h        | hours         |
                   | d        | days (24h)    |
                   | w        | weeks (7d)    |
                   | y        | years (365d)  |

Time units can be combined like so:

prometheus_http_requests_total{handler="/metrics"} [1m30s]

Offset modifier

The offset modifier is used to shift the time offset for individual instant and range vectors in a query.

prometheus_http_requests_total{handler="/metrics"} offset 10m

This query returns a sample that was taken 10 minutes in the past relative to the current time.

The query returned a result that was collected 10 minutes ago. To better understand how it works below I executed a query that returned a range vector with a range of 11 minutes. When we get the timestamp and convert it to date time it will be a date and time exactly 10 min ago.

In the same way, the offset can be applied to a range vector:

prometheus_http_requests_total{handler="/metrics"}[1m] offset 10m

Binary arithmetic operators

The following binary operators can be applied in PromQL with scalar and instant vectors

                   | Operator | Meaning       |
                   | -------- | --------------|
                   | +        | addition      |
                   | -        | substraction  |
                   | *        | multiplication|
                   | /        | division      |
                   | %        | modulo        |
                   | ^        | power         |

Used with scalar values it will result in a scalar value.

When applied with a scalar value and instant vector the scalar value is applied to each element of an instant vector

prometheus_http_requests_total{handler=~".*v1.*"}+1

When we apply a binary operator with instant vectors the result is going to be a new vector containing elements that are present in both vectors.

Comparison operators

The following comparison operators can be applied

                   | Operator | Meaning             |
                   | -------- | --------------------|
                   | ==       | equals              |
                   | !=       | not equals          |
                   | >        | grater-than         |
                   | <=       | less-than           |
                   | >=       | grater-than or equal|
                   | <=       | less-than or equal  |

Applied to the scalar value will give a boolean value (0-false, 1-true). When using those operators with scalars we have to add a special “bool” modifier.

When the operator is used with scalar and instant vectors the result of the query will be a new vector with only values that are matching to the applied operator.

prometheus_http_requests_total==7

When we apply a comparison operator with instant vectors the result is going to be a new vector containing elements that are present in both vectors.

Set binary operators

Can only be applied to Instant Vectors:

| Operator|                     Meaning                                       |
| --------| ------------------------------------------------------------------|
| and     | new vector with element that matches in both                      |
| or      | new vector which is the union of all unique elements              |
| unless  | new vector which elements which are not present on the left side  |

When running the following query no result will be found, because there are no matching elements in both vectors

prometheus_http_requests_total{handler="/api/v1/query"} AND prometheus_http_requests_total{handler="/metrics"}

When using the OR operator the result will be as follow

This query returns all elements present in both vectors. And the query with the Unless operator returns elements from the left side vector that are not present in the right side vector.

Aggregation operators

Prometheus has a wide variety o aggregation operators that can be applied to instant vectors. The sum aggregator calculates the sum of all elements in the vector.

sum(prometheus_http_requests_total)

Min and max aggregators calculate the lowest and highest value in the vector:

min(prometheus_http_requests_total)
max(prometheus_http_requests_total)

The avg calculates the average of the vector:

avg(prometheus_http_requests_total)

The count aggregator returns the number of elements in the vector

count(prometheus_http_requests_total)

The aggregator count_values counts a number of elements in the vector with the same value.

count_values ("prometheus_http_requests_total", prometheus_http_requests_total)

The aggregator tork returns n largest values from the vector:

topk(2,prometheus_http_requests_total)

And the bottomk works in the opposite way

bottomk(2,prometheus_http_requests_total)

The operator group does what its name says groups elements and returns 1

group(prometheus_http_requests_total)

We can aggregate a vector by specific labels, like so by appending a “by” modifier.

sum(prometheus_http_requests_total) by (code)

If we want to exclude some labels we can add a special modifier “without”:

sum(prometheus_http_requests_total) without (code)

We can use aggregators over time for range vectors such as

avg_over_time(prometheus_http_requests_total[10s])

This aggregator calculates the average in the vector in a specified range.

Prometheus has plenty of aggregators that can be applied to range vectors. They are sum_over_time, min_over_time, max_over_time, count_over_time, and many more.

Functions

Prometheus offers us a wide variety of functions. The first function that we going to check is absent. This function checks if an instant vector has any elements. Returns an empty vector when a vector passed to this function contains elements and returns 1 when a vector doesn't have values.

absent(prometheus_http_requests_total)

If we need to get the same result but for a range vector, we have to use the following function:

Prometheus has mathematic functions such as abs, ceil, and floor.

The function clamp converts the lowest values to the value specified as a second parameter and converts the largest values specified as a third parameter.

clamp(prometheus_http_requests_total{handler=~"/metrics|/api/v1/labels|/api/v1/format_query"},3,6000)

From the screen, we can see that this function converted the highest sample from 6162 to 6000 and the lowest from 2 to 3.

There are 2 more versions of this function clamp_min and clamp_max

clamp_min(prometheus_http_requests_total{handler=~"/metrics|/api/v1/labels|/api/v1/format_query"},3)
clamp_max(prometheus_http_requests_total{handler=~"/metrics|/api/v1/labels|/api/v1/format_query"},6000)

Those functions will make graphics look a bit nicer, by removing extreme spikes.

Prometheus has a set of functions to work with date and time, such as day_of_month, day_of_week, and more.

Day of month returns the day of the month (1–31) for every timestamp in a UTC format. And the day of the week returns the day of the week (1–7) for every timestamp in UTC format.

The time function returns near the current timestamp

The function timestamp returns the timestamp on which each element of a vector was sampled.

timestamp(prometheus_http_requests_total)

If we need to sort the instant vector we can use sort and sort_desc functions. First sorts the vector in ascending order and the second in descending order.

sort(prometheus_http_requests_total{handler=~"/metrics|/api/v1/labels|/api/v1/format_query"})
sort_desc(prometheus_http_requests_total{handler=~"/metrics|/api/v1/labels|/api/v1/format_query"})

The complete project can be found here:

Conclusion

This tutorial is about PromQL, a tool that can help you extract important information from the metric of your system. It also helps to create a visualization of metrics and define alarms that will alert you about a problem in your system.

Thank you for reading! Please like and follow. If you have any questions or suggestions, please feel free to write in the comments section or on my LinkedIn account.

Become a member for full access to Medium content.

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job

Prometheus
Metrics
Logs
Microservices
Programming
Recommended from ReadMedium