Prometheus

How to send metrics to Prometheus.

Key takeaways

PrometheusCounters Component used to create different metrics or counters.
PrometheusMetricsService Component used to send metrics to /metrics.
increment Method used to create a counter that increases according to a given number.
incrementOne Method used to create a counter that increases by one.
timestamp Method used to create a counter with the timestamp format.
timestampNow Method used to create a counter that stores the current date and time in a timestamp format.
beginTiming and endTiming Method used to create a counter that measures an interval of time, such as execution time.
dump Method used to store obtained metrics.
setInterval Method used to set an interval for dumps.

Introduction

In this tutorial, you will learn how to send different metrics to Prometheus. First, we will see how to do this via the Pushgateway. Then, we will understand how to show our metrics on a /metrics page. Finally, we will go through a set of different methods, which are useful to create different counters.

Sending metrics to Pushgateway

One of the options presented by Prometheus is to send metrics directly to its Pushgateway interface. For this, Pip.Services has the PrometheusCounters component, which allows us to define different types of counters and send their values to it. The following sections explain how to do this.

Pre-requisites

In order to send our counters to Prometheus, we need to import the PrometheusCounters component. The following command shows how to do this.

import { PrometheusCounters } from "pip-services3-prometheus-nodex";
using PipServices3.Prometheus.Count;
import (
    pcount "github.com/pip-services3-gox/pip-services3-prometheus-gox/count"
)
import 'package:pip_services3_prometheus/pip_services3_prometheus.dart';
from pip_services3_prometheus.count import PrometheusCounters
Not available

Adding the counters to our component

Once we have imported our component, we can create a class containing one or more counters. In our example, we create a class named “MyComponent”, which contains a method called “mymethod”. Within this method, we include two metrics. One is a counter that measures the number of calls to this method, and the other is a variable that measures execution time.

class MyComponentA {
    public consoleLog: boolean = true;
    private counters: CachedCounters;

    public constructor(counter: CachedCounters) {
        this.counters = counter;

        if (this.consoleLog)
            console.log("MyComponentA has been created.");
    }

    public myMethod(): void {
        this.counters.increment("mycomponent.mymethod.calls", 1);
        var timing = this.counters.beginTiming("mycomponent.mymethod.exec_time");

        try {
            if (this.consoleLog) {
                console.log("Hola amigo");
                console.log("Bonjour mon ami");
            }
        } finally {
            timing.endTiming();
        }

        this.counters.dump();
    }
}

using PipServices3.Components.Count;

public class MyComponentA
{
    public bool ConsoleLog = true;

    private CachedCounters counters;
    public MyComponentA(CachedCounters counter)
    {
        counters = counter;

        if (ConsoleLog)
            Console.WriteLine("MyComponentA has been created.");
    }

    public void MyMethod()
    {
        counters.Increment("mycomponent.mymethod.calls", 1);
        var timing = counters.BeginTiming("mycomponent.mymethod.exec_time");

        try
        {
            if (ConsoleLog)
            {
                Console.WriteLine("Hola amigo");
                Console.WriteLine("Bonjour mon ami");
            }
        } finally { 
            timing.EndTiming(); 
        }

        counters.Dump();
    }
}

import (
	"context"
	"fmt"

	pcount "github.com/pip-services3-gox/pip-services3-prometheus-gox/count"
)

type MyComponentA struct {
	counters *pcount.PrometheusCounters

	ConsoleLog bool
}

func NewMyComponentA(counter *pcount.PrometheusCounters) *MyComponentA {
	c := MyComponentA{
		counters:   counter,
		ConsoleLog: true,
	}
	if c.ConsoleLog {
		fmt.Println("MyComponentA has been created.")
	}
	return &c
}

func (c *MyComponentA) MyMethod(ctx context.Context) {
	c.counters.Increment(ctx, "mycomponent.mymethod.calls", 1)
	timing := c.counters.BeginTiming(ctx, "mycomponent.mymethod.exec_time")

	defer timing.EndTiming(ctx)

	if c.ConsoleLog {
		fmt.Println("Hola amigo")
		fmt.Println("Bonjour mon ami")
	}

	c.counters.Dump(ctx)
}
class MyComponentA {
  bool consoleLog = true;
  CachedCounters counters;

  MyComponentA(this.counters) {
    if (consoleLog) print('MyComponentA has been created.');
  }

  void myMethod() {
    counters.increment('mycomponent.mymethod.calls', 1);
    var timing = counters.beginTiming('mycomponent.mymethod.exec_time');

    try {
      if (consoleLog) {
        print('Hola amigo');
        print('Bonjour mon ami');
      }
    } finally {
      timing.endTiming();
    }

    counters.dump();
  }
}

from pip_services3_components.count import CachedCounters

class MyComponentA:
    _console_log = True

    def __init__(self, counters: CachedCounters):
        self.counters = counters

        if _console_log:
            print("MyComponentA has been created.")

    def mymethod(self):
        self.counters.increment("mycomponent.mymethod.calls", 1)
        timing = self.counters.begin_timing("mycomponent.mymethod.exec_time")
        try:
            if _console_log:
                print("Hola amigo")
                print("Bonjour mon ami")
        finally:
            timing.end_timing()
        self.counters.dump()
Not available

Defining and connecting the counter

Once we have our component with the necessary counters, we create an instance of it and connect this object to Prometheus. To do this, we use the configure() method to provide the connection information and the open() method to connect it.

import { PrometheusCounters } from "pip-services3-prometheus-nodex";

let counters = new PrometheusCounters();
counters.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
));

await counters.open(null);

let mycomponent = new MyComponentA(counters);
using PipServices3.Commons.Config;

var counters = new PrometheusCounters();
counters.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
));

await counters.OpenAsync(null);

var mycomponent = new MyComponentA(counters);
import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	pcount "github.com/pip-services3-gox/pip-services3-prometheus-gox/count"
)

func main() {
	counters := pcount.NewPrometheusCounters()
	counters.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 8080,
	))

	_ = counters.Open(context.Background(), "123")

	myComponentA := NewMyComponentA(counters)
}
import 'package:pip_services3_prometheus/pip_services3_prometheus.dart';

var counters = PrometheusCounters();

counters.configure(ConfigParams.fromTuples([
  'connection.protocol',
  'http',
  'connection.host',
  'localhost',
  'connection.port',
  8080
]));

await counters.open(null);

var mycomponent = MyComponentA(counters);
from pip_services3_commons.config import ConfigParams

counters = PrometheusCounters()
counters.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
))

counters.open("123")

mycomponent = MyComponentA(counters)
Not available

Calling the method

Now that we are connected, we can call “mymethod” one or more times. In the example below, we call it twice.

let execCount = 2;

for (let i = 0; i < execCount; i++)
    mycomponent.myMethod();
var execCount = 2;

for (int i = 0; i < execCount; i++)
{
    mycomponent.MyMethod();
}

execCount := 2

for i := 0; i < execCount; i++ {
	myComponentA.MyMethod(context.Background())
}

var execCount = 2;

for (var i = 0; i < execCount; i++) {
  mycomponent.myMethod();
}
count_exec = 2

for i in range(count_exec):
    mycomponent.mymethod()
Not available

Results on console

And, after running our code we get the following messages on our console:

figure 1

Obtaining and analyzing the results

We can get the counters with the getAll() method, which returns a list containing all the counters used.

let result = counters.getAll();
var result = counters.GetAll();
result := counters.GetAll()
var result = counters.getAll();
result = counters.get_all()
Not available

Once we have our list of counters, we can obtain some information from them via the count, min, max, average, time, name and type methods. The following example shows how to obtain these values

for (let item of result)
{
    console.log(item.count);
    console.log(item.min);
    console.log(item.max);
    console.log(item.average);
    console.log(item.time);
    console.log(item.name);
    console.log(item.type);
    console.log("-----------------");
}


foreach (var item in result)
{
    Console.WriteLine(item.Count);
    Console.WriteLine(item.Min);
    Console.WriteLine(item.Max);
    Console.WriteLine(item.Average);
    Console.WriteLine(item.Time);
    Console.WriteLine(item.Name);
    Console.WriteLine(item.Type);
    Console.WriteLine("-----------------");
}


for _, item := range result {
	fmt.Println(item.Count)
	fmt.Println(item.Min)
	fmt.Println(item.Max)
	fmt.Println(item.Average)
	fmt.Println(item.Time)
	fmt.Println(item.Name)
	fmt.Println(item.Type)
	fmt.Println("-----------------")
}

for (var item in result) {
  print(item.count);
  print(item.min);
  print(item.max);
  print(item.average);
  print(item.time);
  print(item.name);
  print(item.type);
  print('-----------------');
}

i = 0

while i < len(result):
    print(result[i].count)
    print(result[i].min)
    print(result[i].max)
    print(result[i].average)
    print(result[i].time)
    print(result[i].name)
    print(result[i].type)
    print("-----------------")
    i += 1
Not available

Which after running presents the following values for the previously defined metrics:

figure 2

Pushgateway results

If we are connected to the Prometheus' Pushgateway, we will find our metrics reflected in its interface. Thus, for example, in the image below, we can see the counter value of two, which indicates that the method was called twice, as we did before in our code.

figure 3

Closing counters

Finally, to finish our code, we close the counters object to free resources.

await counters.close(null);
await counters.CloseAsync("123");
err := counters.Close(context.Background(), "123")
await counters.close(null);
counters.close("123")
Not available

Sending metrics to /metrics

Another option presented by Prometheus is to store the metric values on a page located at /metrics. For this purpose, Pip.Services offers the PrometheusMetricsService. Its use is explained in the following sections.

Pre-requisites

In order to use the PrometheusMetricsService component, we need to import it first. This can be done with the following command:

import { PrometheusMetricsService } from "pip-services3-prometheus-nodex";
using PipServices3.Prometheus.Services;
import (
    pservice "github.com/pip-services3-gox/pip-services3-prometheus-gox/services"
)
import 'package:pip_services3_prometheus/pip_services3_prometheus.dart';
from pip_services3_prometheus.services import PrometheusMetricsService
Not available

Creating the component and the counters

As we did in the previous example, to send metrics to Prometheus, we need to create a component that generates these metrics first. We also need to create and configure a PrometheusCounters object. The following code shows how to do this:

export async function main() {
    let counters = new PrometheusCounters();
    counters.configure(ConfigParams.fromTuples(
        "connection.protocol", "http",
        "connection.host", "localhost",
        "connection.port", 8080
    ));

    await counters.open(null);

    let mycomponent = new MyComponentA(counters);
}

export class MyComponentA {
    public consoleLog: boolean = true;
    private counters: CachedCounters;

    public constructor(counter: CachedCounters) {
        this.counters = counter;

        if (this.consoleLog)
            console.log("MyComponentA has been created.");
    }

    public myMethod(): void {
        this.counters.increment("mycomponent.mymethod.calls", 1);
        var timing = this.counters.beginTiming("mycomponent.mymethod.exec_time");

        try {
            if (this.consoleLog) {
                console.log("Hola amigo");
                console.log("Bonjour mon ami");
            }
        } finally {
            timing.endTiming();
        }

        this.counters.dump();
    }
}
namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var counters = new PrometheusCounters();
            counters.Configure(ConfigParams.FromTuples(
                "connection.protocol", "http",
                "connection.host", "localhost",
                "connection.port", 8080
            ));

            counters.OpenAsync(null).Wait();

            var mycomponent = new MyComponentA(counters);
        }
    }

    public class MyComponentA
    {
        public bool ConsoleLog = true;

        private CachedCounters counters;
        public MyComponentA(CachedCounters counter)
        {
            counters = counter;

            if (ConsoleLog)
                Console.WriteLine("MyComponentA has been created.");
        }

        public void MyMethod()
        {
            counters.Increment("mycomponent.mymethod.calls", 1);
            var timing = counters.BeginTiming("mycomponent.mymethod.exec_time");

            try
            {
                if (ConsoleLog)
                {
                    Console.WriteLine("Hola amigo");
                    Console.WriteLine("Bonjour mon ami");
                }
            } finally { 
                timing.EndTiming(); 
            }

            counters.Dump();
        }
    }
}
package main

import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	pcount "github.com/pip-services3-gox/pip-services3-prometheus-gox/count"
)

func main() {
	counters := pcount.NewPrometheusCounters()
	counters.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 8080,
	))

	err := counters.Open(context.Background(), "123")

	if err != nil {
		fmt.Println(err)
	}

	myComponentA := NewMyComponentA(counters)
}

type MyComponentA struct {
	counters *pcount.PrometheusCounters

	ConsoleLog bool
}

func NewMyComponentA(counter *pcount.PrometheusCounters) *MyComponentA {
	c := MyComponentA{
		counters:   counter,
		ConsoleLog: true,
	}
	if c.ConsoleLog {
		fmt.Println("MyComponentA has been created.")
	}
	return &c
}

func (c *MyComponentA) MyMethod(ctx context.Context) {
	c.counters.Increment(ctx, "mycomponent.mymethod.calls", 1)
	timing := c.counters.BeginTiming(ctx, "mycomponent.mymethod.exec_time")

	defer timing.EndTiming(ctx)

	if c.ConsoleLog {
		fmt.Println("Hola amigo")
		fmt.Println("Bonjour mon ami")
	}

	c.counters.Dump(ctx)
}

void main(List<String> argument) async {
  var counters = PrometheusCounters();
  counters.configure(ConfigParams.fromTuples([
    'connection.protocol',
    'http',
    'connection.host',
    'localhost',
    'connection.port',
    8080
  ]));

  await counters.open(null);

  var mycomponent = MyComponentA(counters);
}

class MyComponentA {
  bool consoleLog = true;
  CachedCounters counters;

  MyComponentA(this.counters) {
    if (consoleLog) print('MyComponentA has been created.');
  }

  void myMethod() {
    counters.increment('mycomponent.mymethod.calls', 1);
    var timing = counters.beginTiming('mycomponent.mymethod.exec_time');

    try {
      if (consoleLog) {
        print('Hola amigo');
        print('Bonjour mon ami');
      }
    } finally {
      timing.endTiming();
    }

    counters.dump();
  }
}


class MyComponentA:
    _console_log = True

    def __init__(self, counters: CachedCounters):
        self.counters = counters

        if self._console_log:
            print("MyComponentA has been created.")

    def mymethod(self):
        self.counters.increment("mycomponent.mymethod.calls", 1)
        timing = self.counters.begin_timing("mycomponent.mymethod.exec_time")
        try:
            if self._console_log:
                print("Hola amigo")
                print("Bonjour mon ami")
        finally:
            timing.end_timing()
        self.counters.dump()


counters = PrometheusCounters()
counters.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
))

mycomponent = MyComponentA(counters)
Not available

Creating the service

To create the /metrics page, we need to create an instance of the PrometheusMetricsService component and configure it. In the following example, we specify that our /metrics page will be located on our machine and connected via port 8080. We also say that this page will show the results obtained from the counters object. Our code is as follows:

let service = new PrometheusMetricsService();

service.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
));
var service = new PrometheusMetricsService();

service.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
));
service := pservice.NewPrometheusMetricsService()

service.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
	"connection.protocol", "http",
	"connection.host", "localhost",
	"connection.port", 8080,
))
var service = PrometheusMetricsService();

service.configure(ConfigParams.fromTuples([
  'connection.protocol',
  'http',
  'connection.host',
  'localhost',
  'connection.port',
  8080
]));
service = PrometheusMetricsService()

service.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
))
Not available

Setting the references

To relate the service and the counters, we need to set the references for the contextInfo, counters and service objects. This is done with the following code:

let context_info = new ContextInfo();
context_info.name = "Test";
context_info.description = "This is a test container";

let references = References.fromTuples(
    new Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
    new Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
    new Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
);

service.setReferences(references);
counters.setReferences(references);

var context_info = new ContextInfo();
context_info.Name = "Test";
context_info.Description = "This is a test container";

var references = References.FromTuples(
    new Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
    new Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
    new Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
);

service.SetReferences(references);
counters.SetReferences(references);

contextInfo := cinfo.NewContextInfo()
contextInfo.Name = "Test"
contextInfo.Description = "This is a test container"

references := refer.NewReferencesFromTuples(context.Background(),
	refer.NewDescriptor("pip-services", "context-info", "default", "default", "1.0"), contextInfo,
	refer.NewDescriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
	refer.NewDescriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service,
)

service.SetReferences(context.Background(), references)
counters.SetReferences(context.Background(), references)

var context_info = ContextInfo();
context_info.name = 'Test';
context_info.description = 'This is a test container';

var references = References.fromTuples([
  Descriptor('pip-services', 'context-info', 'default', 'default', '1.0'), context_info,
  Descriptor('pip-services', 'counters', 'prometheus', 'default', '1.0'), counters,
  Descriptor('pip-services', 'metrics-service', 'prometheus', 'default', '1.0'), service
]);

service.setReferences(references);
counters.setReferences(references);

context_info = ContextInfo()
context_info.name = 'Test'
context_info.description = 'This is a test container'

references = References.from_tuples(
    Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
    Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
    Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
)

service.set_references(references)
counters.set_references(references)
Not available

Connecting and calling the method

Now, as we did in the previous example, we connect to Prometheus and call the method twice. In this case, we need to connect both, the counters and service objects. Then, we call mymethod() with a loop. The code is as follows:

await service.open(null);
await counters.open(null);

var countExec = 2;

for (let i = 0; i < countExec; i++)
    mycomponent.myMethod();

await service.OpenAsync(null);
await counters.OpenAsync(null);

var countExec = 2;

for (int i = 0; i < countExec; i++)
    mycomponent.MyMethod();

err := service.Open(context.Background(), "123")
if err != nil {
	fmt.Println(err)
}

err = counters.Open(context.Background(), "123")
if err != nil {
	fmt.Println(err)
}

countExec := 2

for i := 0; i < countExec; i++ {
	myComponentA.MyMethod(context.Background())
}

await service.open(null);
await counters.open(null);

var countExec = 2;

for (var i = 0; i < countExec; i++) {
  mycomponent.myMethod();
}
service.open("123")
counters.open("123")

count_exec = 2

for i in range(count_exec):
    mycomponent.mymethod()
Not available

Closing the resources

Finally, we can free resources by closing both, the counters and service objects.

await counters.close(null);
await service.close(null);
await counters.CloseAsync(null);
await service.CloseAsync(null);
err = service.Close(context.Background(), "123")
if err != nil {
	fmt.Println(err)
}

err = counters.Close(context.Background(), "123")
if err != nil {
	fmt.Println(err)
}
await counters.close(null);
await service.close(null);
counters.close()
service.close()
Not available

/metrics results

The figure below shows the /metrics page containing the example’s counters and their values.

figure 4

Complete code

Below is the complete code for the example.

import { ConfigParams, Descriptor, IReferenceable, IReferences, References } from "pip-services3-commons-nodex";
import { CachedCounters, ContextInfo } from "pip-services3-components-nodex";
import { PrometheusCounters, PrometheusMetricsService } from "pip-services3-prometheus-nodex";


export async function main() {

    let mycomponent = new MyComponentA();

    // Create an instance of PrometheusCounters and configure it
    let counters = new PrometheusCounters();
    counters.configure(ConfigParams.fromTuples(
        "connection.protocol", "http",
        "connection.host", "localhost",
        "connection.port", 8080
    ));

    // Create an instance of PrometheusMetricsService and configure it
    let service = new PrometheusMetricsService();
    service.configure(ConfigParams.fromTuples(
        "connection.protocol", "http",
        "connection.host", "localhost",
        "connection.port", 8080
    ));

    // Create the references
    let context_info = new ContextInfo();
    context_info.name = "Test";
    context_info.description = "This is a test container";

    let references = References.fromTuples(
        new Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
        new Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
        new Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
    );

    service.setReferences(references);
    counters.setReferences(references);
    mycomponent.setReferences(references);

    // Connect the service and counters objects
    await service.open(null);
    await counters.open(null);
    
    //  Run "mymethod"
    var countExec = 2;

    for (let i = 0; i < countExec; i++)
        mycomponent.myMethod();

    // Get the counters
    let result = counters.getAll();

    // close counter, for closing Http client for prometheus
    await counters.close("123");
    // close service for closing Http server
    await service.close(null);
}

class MyComponentA implements IReferenceable {
    public consoleLog: boolean = true; // console log flag
    private counters: CachedCounters;

    public constructor() {

        if (this.consoleLog)
            console.log("MyComponentA has been created.");
    }
    public setReferences(references: IReferences): void {
        this.counters = references.getOneRequired<CachedCounters>(
            new Descriptor("*", "counters", "*", "*", "*")
        );
    }

    public myMethod(): void {
        // Count the number of calls to this method
        this.counters.increment("mycomponent.mymethod.calls", 1);

        // Measure execution time
        var timing = this.counters.beginTiming("mycomponent.mymethod.exec_time");

        // Task for this method: print greetings in two languages.
        try {
            if (this.consoleLog) {
                console.log("Hola amigo");
                console.log("Bonjour mon ami");
            }
        } finally {
            timing.endTiming();
        }
        // Save the values of counters
        this.counters.dump();
    }
}
using System;

using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Components.Count;
using PipServices3.Components.Info;
using PipServices3.Prometheus.Count;
using PipServices3.Prometheus.Services;


namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var mycomponent = new MyComponentA();

            // Create an instance of PrometheusCounters and configure it
            var counters = new PrometheusCounters();
            counters.Configure(ConfigParams.FromTuples(
                "connection.protocol", "http",
                "connection.host", "localhost",
                "connection.port", 8080
            ));

            // Create an instance of PrometheusMetricsService and configure it
            var service = new PrometheusMetricsService();
            service.Configure(ConfigParams.FromTuples(
                "connection.protocol", "http",
                "connection.host", "localhost",
                "connection.port", 8080
            ));

            // Create the references
            var context_info = new ContextInfo();
            context_info.Name = "Test";
            context_info.Description = "This is a test container";

            var references = References.FromTuples(
                new Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
                new Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
                new Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
            );

            service.SetReferences(references);
            counters.SetReferences(references);
            mycomponent.SetReferences(references);

            // Connect the service and counters objects
            service.OpenAsync(null).Wait();
            counters.OpenAsync(null).Wait();

            //  Run "mymethod"
            var countExec = 2;

            for (int i = 0; i < countExec; i++)
                mycomponent.MyMethod();

            // Get the counters
            var result = counters.GetAll();

            
            // close counter, for closing Http client for prometheus
            counters.CloseAsync("123").Wait();
            // close service for closing Http server
            service.CloseAsync(null).Wait();
        }
    }

    public class MyComponentA: IReferenceable
    {
        public bool ConsoleLog = true; // console log flag

        private CachedCounters counters;
        public MyComponentA()
        {
            if (ConsoleLog)
                Console.WriteLine("MyComponentA has been created.");
        }

        public void SetReferences(IReferences references)
        {
            counters = references.GetOneRequired<CachedCounters>(
                new Descriptor("*", "counters", "*", "*", "*")
            );
        }

        public void MyMethod()
        {
            // Count the number of calls to this method
            counters.Increment("mycomponent.mymethod.calls", 1);

            // Measure execution time
            var timing = counters.BeginTiming("mycomponent.mymethod.exec_time");

            // Task for this method: print greetings in two languages.
            try
            {
                if (ConsoleLog)
                {
                    Console.WriteLine("Hola amigo");
                    Console.WriteLine("Bonjour mon ami");
                }
            } finally { 
                timing.EndTiming(); 
            }
            // Save the values of counters
            counters.Dump();
        }
    }
}
package main

import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	cinfo "github.com/pip-services3-gox/pip-services3-components-gox/info"
	pcount "github.com/pip-services3-gox/pip-services3-prometheus-gox/count"
	pservice "github.com/pip-services3-gox/pip-services3-prometheus-gox/services"
)

func main() {

	myComponentA := NewMyComponentA()

	// Create an instance of PrometheusCounters and configure it
	counters := pcount.NewPrometheusCounters()
	counters.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 8080,
	))

	// Create an instance of PrometheusMetricsService and configure it
	service := pservice.NewPrometheusMetricsService()
	service.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 8080,
	))

	// Create the references
	contextInfo := cinfo.NewContextInfo()
	contextInfo.Name = "Test"
	contextInfo.Description = "This is a test container"

	references := refer.NewReferencesFromTuples(context.Background(),
		refer.NewDescriptor("pip-services", "context-info", "default", "default", "1.0"), contextInfo,
		refer.NewDescriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
		refer.NewDescriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service,
	)

	service.SetReferences(context.Background(), references)
	counters.SetReferences(context.Background(), references)
	myComponentA.SetReferences(context.Background(), references)

	// Connect the service and counters objects
	err := service.Open(context.Background(), "123")
	if err != nil {
		fmt.Println(err)
	}

	err = counters.Open(context.Background(), "123")
	if err != nil {
		fmt.Println(err)
	}

	//  Run "mymethod"
	countExec := 2

	for i := 0; i < countExec; i++ {
		myComponentA.MyMethod(context.Background())
	}

	// Get the counters
	result := counters.GetAll()
	fmt.Println(result)

	// close counter, for closing Http client for prometheus
	err = counters.Close(context.Background(), "123")
	if err != nil {
		fmt.Println(err)
	}

	// close service for closing Http server
	err = service.Close(context.Background(), "123")
	if err != nil {
		fmt.Println(err)
	}

}

type MyComponentA struct {
	counters *pcount.PrometheusCounters

	ConsoleLog bool // console log flag
}

func NewMyComponentA() *MyComponentA {
	c := MyComponentA{
		ConsoleLog: true,
	}
	if c.ConsoleLog {
		fmt.Println("MyComponentA has been created.")
	}
	return &c
}

func (c *MyComponentA) SetReferences(ctx context.Context, references refer.IReferences) {
	p, err := references.GetOneRequired(
		refer.NewDescriptor("*", "counters", "prometheus", "*", "*"),
	)

	if p != nil && err == nil {
		c.counters = p.(*pcount.PrometheusCounters)
	}
}

func (c *MyComponentA) MyMethod(ctx context.Context) {

	// Count the number of calls to this method
	c.counters.Increment(context.Background(), "mycomponent.mymethod.calls", 1)

	// Measure execution time
	timing := c.counters.BeginTiming(context.Background(), "mycomponent.mymethod.exec_time")

	defer timing.EndTiming(context.Background())

	// Task for this method: print greetings in two languages.
	if c.ConsoleLog {
		fmt.Println("Hola amigo")
		fmt.Println("Bonjour mon ami")
	}

	// Save the values of counters
	c.counters.Dump(context.Background())
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
import 'package:pip_services3_prometheus/pip_services3_prometheus.dart';

void main(List<String> argument) async {
  var mycomponent = MyComponentA();

  // Create an instance of PrometheusCounters and configure it
  var counters = PrometheusCounters();
  counters.configure(ConfigParams.fromTuples([
    'connection.protocol',
    'http',
    'connection.host',
    'localhost',
    'connection.port',
    8080
  ]));

  // Create an instance of PrometheusMetricsService and configure it
  var service = PrometheusMetricsService();
  service.configure(ConfigParams.fromTuples([
    'connection.protocol',
    'http',
    'connection.host',
    'localhost',
    'connection.port',
    8080
  ]));

  // Create the references
  var context_info = ContextInfo();
  context_info.name = 'Test';
  context_info.description = 'This is a test container';

  var references = References.fromTuples([
    Descriptor('pip-services', 'context-info', 'default', 'default', '1.0'),
    context_info,
    Descriptor('pip-services', 'counters', 'prometheus', 'default', '1.0'),
    counters,
    Descriptor(
        'pip-services', 'metrics-service', 'prometheus', 'default', '1.0'),
    service
  ]);

  service.setReferences(references);
  counters.setReferences(references);
  mycomponent.setReferences(references);

  // Connect the service and counters objects
  await service.open(null);
  await counters.open(null);

  //  Run "mymethod"
  var countExec = 2;

  for (var i = 0; i < countExec; i++) {
    mycomponent.myMethod();
  }

  // Get the counters
  var result = counters.getAll();

  // close service for closing Http server
  await service.close(null);
  // close counter, for closing Http client for prometheus
  await counters.close(null);
}

class MyComponentA implements IReferenceable {
  bool consoleLog = true; // console log flag
  CachedCounters? counters;

  MyComponentA() {
    if (consoleLog) print('MyComponentA has been created.');
  }

  @override
  void setReferences(IReferences references) {
    counters = references.getOneRequired<CachedCounters>(
        Descriptor('*', 'counters', '*', '*', '*'));
  }

  void myMethod() {
    // Count the number of calls to this method
    counters!.increment('mycomponent.mymethod.calls', 1);

    // Measure execution time
    var timing = counters!.beginTiming('mycomponent.mymethod.exec_time');

    // Task for this method: print greetings in two languages.
    try {
      if (consoleLog) {
        print('Hola amigo');
        print('Bonjour mon ami');
      }
    } finally {
      timing.endTiming();
    }

    // Save the values of counters
    counters!.dump();
  }
}

from pip_services3_commons.config import ConfigParams
from pip_services3_commons.refer import Descriptor, References, IReferences
from pip_services3_components.info import ContextInfo
from pip_services3_prometheus.count import PrometheusCounters
from pip_services3_prometheus.services import PrometheusMetricsService

from pip_services3_commons.refer import IReferenceable


class MyComponentA(IReferenceable):
    console_log: bool = True  # console log flag

    def __init__(self):
        self._counters: PrometheusCounters = None
        if self.console_log:
            print("MyComponentA has been created.")

    # Added references for getting counters
    def set_references(self, references: IReferences):
        self._counters = references.get_one_required(
            Descriptor("*", "counters", "*", "*", "*")
        )

    def mymethod(self):
        # Count the number of calls to this method
        self._counters.increment("mycomponent.mymethod.calls", 1)

        # Measure execution time
        timing = self._counters.begin_timing("mycomponent.mymethod.exec_time")

        # Task for this method: print greetings in two languages.
        try:
            if self.console_log:
                print("Hola amigo")
                print("Bonjour mon ami")
        finally:
            timing.end_timing()

        # Save the values of counters
        self._counters.dump()


# Create an instance of the component
mycomponent = MyComponentA()

# Create an instance of PrometheusCounters and configure it
counters = PrometheusCounters()
counters.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
))

# Create an instance of PrometheusMetricsService and configure it
service = PrometheusMetricsService()

service.configure(ConfigParams.from_tuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 8080
))

# Create the references
context_info = ContextInfo()
context_info.name = 'Test'
context_info.description = 'This is a test container'

references = References.from_tuples(
    Descriptor("pip-services", "context-info", "default", "default", "1.0"), context_info,
    Descriptor("pip-services", "counters", "prometheus", "default", "1.0"), counters,
    Descriptor("pip-services", "metrics-service", "prometheus", "default", "1.0"), service
)

service.set_references(references)
counters.set_references(references)
mycomponent.set_references(references)

# Connect the service and counters objects
service.open("123")
counters.open("123")

# Run "mymethod"
count_exec = 2

for i in range(count_exec):
    mycomponent.mymethod()

# Get the counters
result = counters.get_all()

# close service for closing Http server
service.close('123')
# close counter, for closing Http client for prometheus
counters.close('123')


Not available

Main counter methods

Most methods available from the PrometheusCounters component are inherited from its parent class CachedCounters. This section explains the most relevant ones.

increment

This method can be used to create a counter that increments by a specified value. Its syntax is increment(name: string, value: number) where name is the name of the counter and value is the increment number.

An example of its implementation is

counters.increment("mycomponent.mymethod.calls1", 1);
counters.Increment("mycomponent.mymethod.calls1", 1);
counters.Increment(context.Background(), "mycomponent.mymethod.calls1", 1)
counters.increment('mycomponent.mymethod.calls1', 1);
counters.increment("mycomponent.mymethod.calls1", 2)
Not available

where we create a counter named “mycomponent.mymethod.calls1” that increases by two every time it is called.

incrementOne

This method is similar to the previous one, but uses a fixed increment value of one. Its syntax is incrementOne(name: string) where name represents the name of the counter.

For example, we can create a counter called “mycomponent.mymethod.calls2” that increases by one every time it is called:

counters.incrementOne("mycomponent.mymethod.calls2");
counters.IncrementOne("mycomponent.mymethod.calls2");
counters.IncrementOne(context.Background(), "mycomponent.mymethod.calls2")
counters.incrementOne('mycomponent.mymethod.calls2');
counters.increment_one("mycomponent.mymethod.calls2")
Not available

timestamp

This method records a given timestamp. Its syntax is: timestamp(name: string, value: DateTime) where name is the name of the counter and value is the given timestamp.

In the example below, we use this command to create a metric that measures the difference between the current time and a base time.

let diff = new Date(new Date().getTime() - this.baseTime);
counters.timestamp("mycomponent.mymethod.times1", diff);
var diff = new DateTime(0) + DateTime.Now.Subtract(this.baseTime);
counters.Timestamp("mycomponent.mymethod.times1", diff);
diff := time.Unix(0, time.Now().UnixNano() - baseTime)
counters.Timestamp(context.Background(), "mycomponent.mymethod.times1", diff)
var diff = DateTime.fromMillisecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch - this.baseTime);
counters.timestamp('mycomponent.mymethod.times1', diff);
counters.timestamp("mycomponent.mymethod.times1", datetime.datetime.now() - self.baseTime)
Not available

timestampNow

Similar to the previous one, this method records the current time as a timestamp. Its syntax is timestampNow(name: string) where name is the name of the counter.

Using it, the example below shows how to create a metric that measures the current time:

counters.timestampNow("mycomponent.mymethod.times2");
counters.TimestampNow("mycomponent.mymethod.times2");
counters.TimestampNow(context.Background(), "mycomponent.mymethod.times2")
counters.timestampNow('mycomponent.mymethod.times2');
counters.timestamp_now("mycomponent.mymethod.times2")
Not available

beginTiming and endTiming

The beginTiming() method starts the measurement of an execution time interval. It returns a CounterTiming object, which by calling the endTiming() method ends the measurement and updates the counter. Their syntaxes are beginTiming(name: string): CounterTiming and endTiming()

dump

This method saves the current values of counters. Its syntax is dump()

The following example shows how to create a timing for a method named mymethod. Here, we measure the execution time of a task, and then, we save the value with the dump() method.

public myMethod(): void {
   let timing = this.counters.beginTiming("mycomponent.mymethod.exec_time");

   try {
       // our task
   } finally {
       timing.endTiming();
   }
   counters.dump();
}

public void MyMethod()
{
   var timing = counters.BeginTiming("mycomponent.mymethod.exec_time");

   try
   {
      // our task
   }
   finally { 
      timing.EndTiming(); 
   }
   counters.Dump();
}

func MyMethod() {

	timing := counters.BeginTiming(context.Background(), "mycomponent.mymethod.exec_time")

	defer timing.EndTiming(context.Background())

	// our task

	counters.Dump(context.Background())
}

void myMethod() {
  var timing = counters.beginTiming('mycomponent.mymethod.exec_time');

  try {
    // our task
  } finally {
    timing.endTiming();
  }

  counters!.dump();
}

def mymethod(self):
    timing = counters.begin_timing("mycomponent.mymethod.exec_time")
    try:
       # our task
    finally:
       timing.end_timing()
    counters.dump()
Not available

setInterval

This method sets the time interval for the dump() method. Its syntax is setInterval(value: float) where value is the time interval in milliseconds.

In the example below, we use this command to set the interval to one minute.

counters.setInterval(60000);
counters.Configure(ConfigParams.FromTuples(
    "interval", 60000L,
    "..."
));
counters.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
	"interval", 60000,
	"...",
))
counters.setInterval(60000);
counters.set_interval(60000)
Not available

Wrapping up

In this tutorial, we have learned how to send metric values to Prometheus. First, we saw how to send them to its Pushgateway and analyze the results. Then, we learned how to present our metrics on a page under /metrics. Finally, we explored the main methods available for counters.