FreeSWITCH exporter for Prometheus
Why and how we built our own FreeSWITCH exporter
August 23, 2021
TL;DR
- The exporter is available here: https://github.com/florentchauveau/freeswitch_exporter
- Docker images are available here: https://hub.docker.com/r/florentchauveau/freeswitch_exporter/
- MIT licensed
- Contributions welcome
- There’s also our Kamailio exporter
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:
- mod_prometheus (FreeSWITCH module written in Rust)
- prometheus-freeswitch-exporter (Python)
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
- Writing Exporters from Prometheus
- Writing Prometheus Exporters from Percona
- FreeSWITCH mod_event_socket