diff --git a/README.md b/README.md index d89ff3d..1820f53 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,97 @@ # opensips_exporter -Work In Progress +This exporter exposes OpenSIPS metrics for consumption by Prometheus using the Unix socket +provided by OpenSIPS. It uses the +OpenSIPS [Management Interface](http://www.opensips.org/Documentation/Interface-MI-1-11) to gather +these statistics. -Currently, this opensips_exporter doesn't work. More documentation to come. +Tested and developed for OpenSIPS 1.11. Though the Management Interface to gather metrics is available +in other OpenSIPS versions. +## Usage +Make sure `$GOPATH/bin` is in your `$PATH`. +``` +Usage of opensips_exporter: + -path string + The path where metrics will be served (default "/metrics") + -port string + Port on which the OpenSIPS exporter listens. (default "9737") + -socket string + Path to the socket file for OpenSIPS. (default "/var/run/ser-fg/ser.sock") +``` + +## Exported Metrics + +| Metric | Meaning | Labels | +| ------ | ------- | ------ | +| opensips_core_bad_URIs_rcvd | Number of URIs that OpenSIPS failed to parse. | | +| opensips_core_bad_msg_hdr | Number of SIP headers that OpenSIPS failed to parse. | | +| opensips_core_replies | Number of received replies by OpenSIPS. | kind| +| opensips_core_replies_total | Total number of received replies by OpenSIPS. | | +| opensips_core_request | Number of requests by OpenSIPS. | kind | +| opensips_core_requests_total | Total number of received requests by OpenSIPS. | | +| opensips_core_unsupported_methods | Number of non-standard methods encountered by OpenSIPS while parsing SIP methods. | | +| opensips_core_uptime_seconds | Number of seconds elapsed from OpenSIPS starting. | | +| opensips_dialog_dialogs | Number of dialogs. | status | +| opensips_dialog_received | The number of dialog events received from other OpenSIPS instances. | event | +| opensips_dialog_sent | Number of replicated dialog requests send to other OpenSIPS instances. | event | +| opensips_load_load | Percentage of UDP children that are awake and processing SIP messages on the specific UDP interface. |ip, port, protocol| +| opensips_load_tcp_load | Percentage of TCP children that are awake and processing SIP messages. | | +| opensips_net_waiting | Number of bytes waiting to be consumed on an interface that OpenSIPS is listening on. | protocol | +| opensips_pkmem_fragments | Currently available number of free fragments in the private memory for OpenSIPS process. | pid | +| opensips_pkmem_free_size | Free private memory available for the OpenSIPS process. Computed as total_size - real_used_size. | pid | +| opensips_pkmem_max_used_size | The maximum amount of private memory ever used by the OpenSIPS process. | pid | +| opensips_pkmem_real_used_size | Amount of private memory requested by the OpenSIPS process, including allocator-specific metadata. | pid | +| opensips_pkmem_total_size | Total size of private memory available to the OpenSIPS process. | pid | +| opensips_pkmem_used_size | Amount of private memory requested and used by the OpenSIPS process. | pid | +| opensips_registrar_default_expire | Value of default_expire parameter. | | +| opensips_registrar_max_contacts | Value of max_contacts parameter. | | +| opensips_registrar_max_expires | Value of max_expires parameter. | | +| opensips_registrar_registrations | Number of registrations. | type | +| opensips_shmem_fragments | Total number of fragments in the shared memory. | | +| opensips_shmem_free_size | Free memory available. Computed as total_size - real_used_size | | +| opensips_shmem_max_used_size | Maximum amount of shared memory ever used by OpenSIPS processes. | | +| opensips_shmem_real_used_size | Amount of shared memory requested by OpenSIPS processes + malloc overhead | | +| opensips_shmem_total_size | Total size of shared memory available to OpenSIPS processes. | | +| opensips_shmem_used_size | Amount of shared memory requested and used by OpenSIPS processes. | | +| opensips_sl_received_ACKs | The number of received_ACKs. | | +| opensips_sl_replies | The number of replies. | type | +| opensips_sl_sent_err_replies_total | The total number of sent_err_replies. | | +| opensips_sl_sent_replies_total | The total number of sent_replies. | | +| opensips_tm_inuse_transactions | Number of transactions existing in memory at current time. | | +| opensips_tm_local_replies_total | Total number of replies local generated by TM module. | | +| opensips_tm_received_replies_total | Total number of total replies received by TM module. | | +| opensips_tm_relayed_replies_total | Total number of replies received and relayed by TM module. | | +| opensips_tm_transactions_total | Total number of transactions. | type | +| opensips_uri_negative_checks | Amount of negative URI checks. | | +| opensips_uri_positive_checks | Amount of positive URI checks. | | +| opensips_userloc_registered_users_total | Total number of AOR existing in the USRLOC memory cache for all domains. | | +| opensips_usrloc_contacts | Number of contacts existing in the USRLOC memory cache for that domain. | domain | +| opensips_usrloc_expires | Total number of expired contacts for that domain. | domain | +| opensips_usrloc_users | Number of AOR existing in the USRLOC memory cache for that domain. | domain | + +## Processors + +There are processors available per 'module' of OpenSIPS. The processors take the +statistics from the OpenSIPS socket and turn it into a Prometheus metric. You can +recognise a processor by the naming convention of the metrics. +For example the`opensips_core_replies` metric comes from the core module and its +processor can be found in `./processors/core_processor`. + +You can find out more about the available modules in the OpenSIPS documentation. +At this time not all modules have a processor written for them. (help wanted!) + +### Filtering enabled processors +It is possible to select what processors you want metrics from. You can do this by +appending `collect[]` parameters to your request. If for example you only want to +get metrics about the [core](http://www.opensips.org/Documentation/Interface-CoreStatistics-1-11) +and [usrloc](http://www.opensips.org/html/docs/modules/1.11.x/usrloc.html#idp5699792) +module you can do this as follows: +``` +curl localhost:9737/metrics?collect[]=core:&collect[]=usrloc: +``` + +**_Note: You have to append `:` to the module name for this to work._** ## Development To work on opensips_exporter, get a recent [Go], get a recent [dep], and @@ -19,5 +107,10 @@ implementation of the interactions with OpenSIPS needed to get statistics from the mi_datagram Unix socket of a running OpenSIPS. For tests, there is a mock in the `./internal/mock` package. +Metrics from different OpenSIPS modules are extracted by processors defined in +the `./processors` package. To extend this exporter with metrics from other modules +create your own processor and implement the `Collector` interface. See the other +processors for inspiration. + [Go]: https://golang.org/doc/install (Getting Started - The Go Programming Language) [dep]: https://golang.github.io/dep/docs/installation.html (Installation ยท dep) diff --git a/opensips_exporter.go b/opensips_exporter.go index 553b8a2..5a98fde 100644 --- a/opensips_exporter.go +++ b/opensips_exporter.go @@ -5,6 +5,10 @@ import ( "log" "net/http" + "flag" + "os" + "strings" + "github.com/VoIPGRID/opensips_exporter/opensips" "github.com/VoIPGRID/opensips_exporter/processors" "github.com/prometheus/client_golang/prometheus" @@ -14,6 +18,8 @@ import ( var o *opensips.OpenSIPS var collectAll = []string{"core:", "shmem:", "net:", "uri:", "tm:", "sl:", "usrloc:", "dialog:", "registrar:", "pkmem:", "load:"} +const envPrefix = "OPENSIPS_EXPORTER" + func handler(w http.ResponseWriter, r *http.Request) { collect := r.URL.Query()["collect[]"] collectors := make(map[prometheus.Collector]bool) @@ -58,28 +64,45 @@ func handler(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) } +// strflag is like flag.String, with value overridden by an environment +// variable (when present). e.g. with socket path, the env var used as default +// is OPENSIPS_EXPORTER_SOCKET_PATH, if present in env. +func strflag(name string, value string, usage string) *string { + if v, ok := os.LookupEnv(envPrefix + strings.ToUpper(name)); ok { + return flag.String(name, v, usage) + } + return flag.String(name, value, usage) +} + +var ( + socketPath *string + metricsPath *string + port *string +) + func main() { - listenAddress := ":9737" // TODO: make this a flag - metricsPath := "/metrics" // TODO: maybe make this a flag - socketPath := "/var/run/ser-fg/ser.sock" // TODO: make this a flag or even a mandatory argument + port = strflag("port", "9737", "Port on which the OpenSIPS exporter listens.") + metricsPath = strflag("path", "/metrics", "The path where metrics will be served") + socketPath = strflag("socket", "/var/run/ser-fg/ser.sock", "Path to the socket file for OpenSIPS.") + flag.Parse() // This part is to mock up setting up and using the Management // Interface. Replace/remove this eventually. var err error - o, err = opensips.New(socketPath) + o, err = opensips.New(*socketPath) if err != nil { log.Fatalf("failed to open socket: %v\n", err) } - http.HandleFunc(metricsPath, handler) + http.HandleFunc(*metricsPath, handler) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(` OpenSIPS Exporter

OpenSIPS Exporter

-

Metrics

+

Metrics

`)) }) - http.ListenAndServe(listenAddress, nil) + http.ListenAndServe(":"+*port, nil) } diff --git a/processors/registrar_processor.go b/processors/registrar_processor.go index df8349d..bf043e3 100644 --- a/processors/registrar_processor.go +++ b/processors/registrar_processor.go @@ -11,9 +11,9 @@ type RegistrarProcessor struct { var registrarLabelNames = []string{} var registrarMetrics = map[string]metric{ - "max_expires": newMetric("registrar", "max_expires", " Value of max_expires parameter.", registrarLabelNames, prometheus.GaugeValue), - "max_contacts": newMetric("registrar", "max_contacts", " Value of max_contacts parameter.", registrarLabelNames, prometheus.GaugeValue), - "default_expire": newMetric("registrar", "default_expire", " Value of default_expire parameter.", registrarLabelNames, prometheus.GaugeValue), + "max_expires": newMetric("registrar", "max_expires", "Value of max_expires parameter.", registrarLabelNames, prometheus.GaugeValue), + "max_contacts": newMetric("registrar", "max_contacts", "Value of max_contacts parameter.", registrarLabelNames, prometheus.GaugeValue), + "default_expire": newMetric("registrar", "default_expire", "Value of default_expire parameter.", registrarLabelNames, prometheus.GaugeValue), "accepted_regs": newMetric("registrar", "registrations", "Number of registrations.", []string{"type"}, prometheus.CounterValue), "rejected_regs": newMetric("registrar", "registrations", "Number of registrations.", []string{"type"}, prometheus.CounterValue), }