FreeSWITCH exporter for Prometheus

Why and how we built our own FreeSWITCH exporter

August 23, 2021

TL;DR

The FreeSWITCH Exporter

Why

In a previous blog post, we explained why we are now using Prometheus, an open source systems monitoring.

FreeSWITCH does not provide a native exporter for Prometheus, we have to use an external one. At the time we were looking for one, the options were:

The Rust one clearly says that it is not ready for production use. The python one was more likely a candidate, but we were missing some metrics (in particular one that says if freeswitch time is in sync with the system time. Also, the min_idle_cpu one).

Because of our experience with the Kamailio exporter written in Go, we felt we could build a powerful, stable exporter for FreeSWITCH pretty quickly.

The Event Socket

FreeSWITCH exposes its API through an network layer called the Event Socket. The protocol is fairly simple to parse. It is text-based, with a MIME style header (Key: Value), an optional Content-Length header, and in that case, a body.

All of the API commands we are using are returning a body.

Here is our method to communicates with FreeSWITCH:

func (c *Collector) fsCommand(command string) ([]byte, error) {
	_, err := io.WriteString(c.conn, command+"\n\n")

	if err != nil {
		return nil, fmt.Errorf("cannot write command: %w", err)
	}

	mimeReader := textproto.NewReader(c.input)
	message, err := mimeReader.ReadMIMEHeader()

	if err != nil {
		return nil, fmt.Errorf("cannot read command response: %w", err)
	}

	value := message.Get("Content-Length")
	length, _ := strconv.Atoi(value)

	body := make([]byte, length)
	_, err = io.ReadFull(c.input, body)

	if err != nil {
		return nil, err
	}

	return body, nil
}

After sending the command, we are using ReadMIMEHeader from the textproto package to read the reply. It allows us to fetch the Content-Length header fairly simply, and then read the full body with io.ReadFull. The body is returned as []byte, and then used in the collector to expose metrics.

The Metrics

Every time the exporter needs to access FreeSWITCH metrics, it performs the following API commands:

  • api show calls count
  • api uptime s
  • api strepoch
  • status

The following metrics are then exposed:

  • current_calls
  • uptime_seconds
  • time_synced
  • sessions_total
  • current_sessions
  • current_sessions_peak
  • current_sessions_peak_last_5min
  • current_sps
  • current_sps_peak
  • current_sps_peak_last_5min
  • max_sps
  • max_sessions
  • current_idle_cpu
  • min_idle_cpu

They are all gauge metrics, except for the sessions_total which is a counter.

Download

The exporter is available here: https://github.com/florentchauveau/freeswitch_exporter.

Pre-compiled binaries are available in releases.

Docker images are available on DockerHub.

Further Reading

Thanks for reading!

I am currently hiring a devops engineer to help me build the future of telcos at Callr.

Do you speak French and English, love what you do and know a thing or two about Unix, Docker, Ansible and software engineering?

Reach out to me and let's have a chat.