Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
fluxxcode committed Dec 18, 2023
0 parents commit ea402e3
Show file tree
Hide file tree
Showing 23 changed files with 2,818 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Virtual envirnoment
/.venv/

# Python
__pycache__/
*.pyc

22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM python:3.8.10-alpine

ENV POETRY_VERSION=1.7.1

RUN apk update && apk add gcc musl-dev libffi-dev
RUN addgroup -S dev && adduser -S dev -G dev

USER dev

RUN pip3 install --upgrade pip

ADD --chown=dev:dev poetry.lock pyproject.toml /home/dev/asterisk-prometheus-exporter/
WORKDIR /home/dev/asterisk-prometheus-exporter/
ENV PATH="/home/dev/.local/bin/:${PATH}"

RUN pip3 install --user "poetry==$POETRY_VERSION"
RUN poetry install --only main

ADD --chown=dev:dev src ./src
CMD ["poetry", "run", "python", "src/main.py"]

EXPOSE 8080
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2023 GONICUS GmbH

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143 changes: 143 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Asterisk prometheus exporter
Repository that provides a dynamically configurable Prometheus exporter for Asterisk. The exporter uses the Asterisk Manager Interface (AMI) to communicate with Asterisk and YAML files to configure what data is scraped from Asterisk and what metrics are generated. This allows the exporter to be used with older Asterisk versions in different environments.

## Installation
### Python Poetry
The exporter uses Poetry as it's dependency management. Head over to [Poetry](https://python-poetry.org/) to install the latest version for your desired platform.

Install the required dependencies using Poetry:
```
poetry install
```

Start the exporter:
```
poetry run python src/main.py
```
The configured metrics can be accessed at http://localhost:8080.

By default, the exporter loads the configuration `config.yml` and uses port 8080. \
A different port can be specified via the first positional argument: `poetry run python src/main.py 9090`. \
A different configuration can be set using the `--config` option: `poetry run python src/main.py --config path/to/config.yml`.

### Docker
Create a Docker image using the provided Dockerfile:
```
docker build --tag asterisk-prometheus-exporter .
```

Run the Docker image and mount the configuration:
```
docker run -p 8080:8080 -v ./config.yml:/home/dev/asterisk-prometheus-exporter/config.yml asterisk-prometheus-exporter
```
The configured metrics can be accessed at http://localhost:8080.

## Configuration
This section shows the rough structure of the configuration. See `src/config_schema.yml` for a detailed description of the configuration and what is possible.

Before customizing the configuration, it is recommended to have a rough overview of the Asterisk Manager Interfance (AMI) and how it works. The next section uses AMI terms that will not be explained further.

The configuration is generally structured in such a way that it is determined which events sent by the Asterisk are filtered and which metrics should be generated based on the events received and the data they contain.

The first and only required section of the configuration is the `ami_client` section. Here you configure which Asterisk and which access data you should log in with.
```yml
ami_client:
ip: "1.2.3.4"
port: 5038
username: "ami_user"
secret: "test"
```
The `filter` section of the configuration is used to define filter, which are used to collect events from the Asterisk that are send to the AMI client when an event is triggered within the Asterisk. An event that falls under this, for example, is the DialBegin event, which is sent by the Asterisk when a dial action is started. The filters defined in this section are used from the start of the exporter until the end. For each filter, you first define which events should be filter and then which metrics should be generated from the filtered events. \
The following example shows a configuration that counts how many calls are made:
```yml
filter:
- event: "DialBegin"
metrics:
- name: "dial_count"
description: "Total number of started dials"
value:
type: counter # Currently supported open metric types: counter, gauge
increment_value: "1" # Increment the metric value every time a DialBegin event is received
```

The `scrape` section is used to define actions that are send to the AMI in a specific interval. Here you first determine the interval at which the scraping is taking place. A list is then specified which actions should be sent to the AMI, which events should then be filtered and the metrics that should be generated based on the filtered events. The attribute `until` is used to set which event is expected to be the last event of the action. \
The following example shows a configuration that counts how many members are logged into a specific queue:
```yml
scrape:
interval: 15 # Send the actions every 15 seconds
actions:
- name: "QueueStatus" # Action that should be sent
collect:
# Events to filter after sending the action
- event: "QueueMember"
metrics:
- name: "queue_member_count"
description: "Number of members currently logged into a specific queue"
value:
type: gauge
increment_value: "1"
value_on_scrape_start: 0
labels:
- name: "queue"
value: "$Queue" # Use '$' to access attributes from the filtered event
until: "ContactStatusDetailComplete"
```

## Example configuration
Below is an entire example configuration that scrapes the RTCP fraction lost of the known endpoints and counts the number of members currently logged into a specific queue. \
This configuration allows, for example, to send an alert if too few members are logged into a queue or to see whether a user agent has connection problems.
```yml
ami_client:
ip: "1.2.3.4"
port: 5038
username: "ami_user"
secret: "test"
filter:
- event: "RTCPSend|RTCPReceived"
metrics:
- name: "rtcp_endpoint_x_fraction_lost"
description: "Aggregate fraction lost of RTCP events"
value:
type: counter
increment_value: "$Report0FractionLost"
labels:
- name: "endpoint"
value: "$CallerIDNum"
scrape:
interval: 15
actions:
- name: "QueueStatus"
collect:
- event: "QueueMember"
metrics:
- name: "queue_member_count"
description: "Number of members currently logged into a specific queue"
value:
type: gauge
increment_value: "1"
value_on_scrape_start: 0
labels:
- name: "queue"
value: "$Queue"
until: "QueueStatusComplete"
```
The metrics generated based on the configuration might look like this:
```
# HELP rtcp_endpoint_x_fraction_lost_total Aggregate fraction lost of RTCP events
# TYPE rtcp_endpoint_x_fraction_lost_total counter
rtcp_endpoint_x_fraction_lost_total{endpoint="100"} 0.0
rtcp_endpoint_x_fraction_lost_total{endpoint="200"} 255.0
rtcp_endpoint_x_fraction_lost_total{endpoint="300"} 291.0
# HELP rtcp_endpoint_x_fraction_lost_created Aggregate fraction lost of RTCP events
# TYPE rtcp_endpoint_x_fraction_lost_created gauge
rtcp_endpoint_x_fraction_lost_created{endpoint="100"} 1.7026356281841428e+09
rtcp_endpoint_x_fraction_lost_created{endpoint="200"} 1.702635652441021e+09
rtcp_endpoint_x_fraction_lost_created{endpoint="300"} 1.7026356524437878e+09
# HELP queue_member_count Number of members currently logged into a specific queue
# TYPE queue_member_count gauge
queue_member_count{queue="zentrale"} 2.0
queue_member_count{queue="support"} 2.0
```
98 changes: 98 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Base exporter config
ami_client:
ip: "<ip>"
port: 5038
username: '<username>'
secret: '<secret>'

# General config
general:
log_level: "DEBUG"
login_validation_timeout: 10
response_timeout: 10
ping_timeout: 20


# Default settings
default:
scrape_interval: 15
action_response_timeout: 5
action_event_timeout: 15
action_priority: 1
action_context: "default"
action_caller_id: "python"

# Filter config
filter:
- event: "RTCPSend|RTCPReceived"
metrics:
- name: "rtcp_endpoint_x_fraction_lost"
description: "Aggregate fraction lost of RTCP events"
value:
type: counter
increment_value: "$Report0FractionLost"
labels:
- name: "endpoint"
value: "$CallerIDNum"
- name: "rtcp_endpoint_x_cumulative_lost"
description: "Aggregate cumulative lost of RTCP events"
value:
type: counter
increment_value: "$Report0CumulativeLost"
labels:
- name: "endpoint"
value: "$CallerIDNum"

# Action config
scrape:
interval: 15
actions:
- name: "QueueStatus"
collect:
- event: "QueueParams"
metrics:
- name: "queue_total"
description: "Available queues"
value:
type: gauge
set_value: "1"
labels:
- name: "queue"
value: "$Queue"
- event: "QueueMember"
metrics:
- name: "queue_member_count"
description: "Number of members currently logged into a specific queue"
value:
type: gauge
increment_value: "1"
value_on_scrape_start: 0
labels:
- name: "queue"
value: "$Queue"
- event: "QueueEntry"
metrics:
- name: "queue_entry_count"
description: "Number of entries in a specific queue"
value:
type: gauge
increment_value: "1"
value_on_scrape_start: 0
labels:
- name: "queue"
value: "$Queue"
until: "QueueStatusComplete"
- name: "PJSIPShowRegistrationInboundContactStatuses"
collect:
- event: "ContactStatusDetail"
metrics:
- name: "user_agents"
description: "User agents"
value:
type: gauge
increment_value: "1"
value_on_scrape_start: 0
labels:
- name: "user_agent"
value: "$UserAgent"
until: "ContactStatusDetailComplete"
Loading

0 comments on commit ea402e3

Please sign in to comment.