Skip to content

Commit 5c62097

Browse files
author
pavel.chi
committed
done
1 parent b135435 commit 5c62097

File tree

10 files changed

+263
-8
lines changed

10 files changed

+263
-8
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ on:
55
branches:
66
- master
77
pull_request:
8-
8+
99
env:
1010
cache_key: cache-v1
1111

12-
jobs:
12+
jobs:
1313
lint:
1414
runs-on: '${{ matrix.operating_system }}'
15-
strategy:
15+
strategy:
1616
matrix:
1717
operating_system:
1818
- ubuntu-20.04
1919
php_versions:
2020
- '7.4'
2121
fail-fast: false
2222
name: 'Lint'
23-
steps:
23+
steps:
2424
- name: 'Checkout'
2525
uses: actions/checkout@v2
2626
- name: 'Setup PHP'
27-
uses: shivammathur/setup-php@v2
28-
with:
27+
uses: shivammathur/setup-php@v2
28+
with:
2929
php-version: ${{ matrix.php_versions }}
3030
- name: 'Install PHP dependencies with Composer'
3131
run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader
@@ -37,7 +37,7 @@ jobs:
3737
matrix:
3838
operating_system:
3939
- ubuntu-20.04
40-
php_versions:
40+
php_versions:
4141
- '7.4'
4242
runs-on: '${{ matrix.operating_system }}'
4343
name: 'Test / PHP ${{ matrix.php_versions }}'
@@ -68,7 +68,7 @@ jobs:
6868
run: ./vendor/bin/php-coveralls --coverage_clover=build/logs/clover.xml -v
6969
coverage:
7070
needs: test
71-
runs-on:
71+
runs-on:
7272
- ubuntu-20.04
7373
name: "Code coverage"
7474
steps:

.github/workflows/image.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Publish Docker image
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
9+
env:
10+
REGISTRY: ghcr.io
11+
IMAGE_NAME: umbrellio/event-tracker/exporter
12+
13+
jobs:
14+
build-and-push-image:
15+
runs-on: ubuntu-latest
16+
17+
permissions:
18+
contents: read
19+
packages: write
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v2
24+
25+
- name: Log in to the Container Registry
26+
uses: docker/login-action@v1
27+
with:
28+
registry: ${{ env.REGISTRY }}
29+
username: ${{ github.actor }}
30+
password: ${{ secrets.GITHUB_TOKEN }}
31+
32+
- name: Extract metadata (tags, labels) for Docker
33+
id: meta
34+
uses: docker/metadata-action@v3
35+
with:
36+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
37+
38+
- name: Build and push Docker image
39+
uses: docker/build-push-action@v2
40+
with:
41+
context: exporter
42+
push: true
43+
tags: ${{ steps.meta.outputs.tags }}
44+
labels: ${{ steps.meta.outputs.labels }}

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ composer require umbrellio/event-tracker
1919
- Log anything you want by multipurpose classes - EventRepository and PrometheusRepository
2020
- Log into influxdb directly or by telegraf
2121
- Prometheus support
22+
- Application metrics exporter
2223

2324
## Known issues
2425

@@ -31,6 +32,46 @@ composer require umbrellio/event-tracker
3132
1. Execute `php artisan vendor:publish` for publishing config example in your `config` directory
3233
2. Write your credentials and settings in config. If you don't need some connections or trackers you can delete them.
3334

35+
### Prometheus
36+
37+
Each instances of your application must have own storage for your metrics. You cannot use shared storage with several replicas of your application. In that case scraping will return metrics for both the current replica and other replicas.
38+
39+
You could still use shared storage if you have only one fpm replica.
40+
41+
In distributed systems like Kubernetes probably your application is likely running in multiple instances and in different modes (fpm, horizon). Each of them produces metrics and each of them has to be monitored by Prometheus. The exporter provided by this package will solve mentioned above problem. Correct setup should include:
42+
43+
- Each replica has its own (local) redis instance to store metrics
44+
- Each replica has its own exporter which exposes `/metrics`-endpoint and grabs metrics from the redis instance. The provided exporter is available: ghcr.io/umbrellio/event-tracker/exporter:latest
45+
- Application writes metrics to that local redis instance
46+
- `database.php` has separated connection to the local instance
47+
48+
```php
49+
return [
50+
...
51+
'redis' => [
52+
...
53+
'metrics' => [
54+
'host' => env('REDIS_METRICS_HOST', '127.0.0.1'),
55+
'port' => env('REDIS_METRICS_PORT', 6379),
56+
'database' => env('REDIS_METRICS_DATABASE', 0),
57+
],
58+
],
59+
];
60+
```
61+
- `event_tracker.php` has the name of this connection
62+
63+
```php
64+
return [
65+
...
66+
'connections' => [
67+
...
68+
'prometheus' => [
69+
'redis' => 'metrics',
70+
],
71+
],
72+
];
73+
```
74+
3475
## Trackers
3576

3677
### Response time tracker

config/event_tracker.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
],
2929
],
3030
'prometheus' => [
31+
'redis' => 'default',
3132
'labels' => [
3233
'namespace' => 'app_ns',
3334
],

exporter/.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.dockerignore
2+
Dockerfile
3+
docker-compose.yml
4+
vendor/

exporter/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/vendor/

exporter/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
ARG dependency_proxy_prefix="library"
2+
FROM mlocati/php-extension-installer:2.0.2 AS php-extension-installer
3+
FROM $dependency_proxy_prefix/php:8.2-alpine
4+
5+
LABEL maintainer="Umbrellio"
6+
SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
7+
8+
COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
9+
RUN chmod +x /usr/local/bin/install-php-extensions && \
10+
install-php-extensions \
11+
redis
12+
13+
RUN curl -sS https://getcomposer.org/installer \
14+
| php -- --install-dir=/usr/local/bin --filename=composer \
15+
16+
RUN mkdir exporter
17+
WORKDIR /exporter
18+
COPY composer.json composer.lock ./
19+
RUN composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader --quiet
20+
21+
COPY ./ ./
22+
23+
CMD ["php", "-S", "0.0.0.0:8000", "-t", "public"]
24+

exporter/composer.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "umbrellio/exporter",
3+
"type": "project",
4+
"require": {
5+
"php": ">=8.2",
6+
"promphp/prometheus_client_php": "^2.6"
7+
},
8+
"license": "MIT"
9+
}

exporter/composer.lock

Lines changed: 88 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exporter/public/index.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Prometheus\CollectorRegistry;
6+
use Prometheus\RenderTextFormat;
7+
use Prometheus\Storage\Redis as RedisAdapter;
8+
9+
require __DIR__ . '/../vendor/autoload.php';
10+
11+
$uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
12+
13+
if ($uri === '/healthcheck') {
14+
echo 'ok';
15+
16+
return;
17+
}
18+
19+
if ($uri !== '/metrics') {
20+
http_response_code(404);
21+
22+
return;
23+
}
24+
25+
$config = [
26+
'host' => getenv('REDIS_HOST') ?: '127.0.0.1',
27+
'port' => getenv('REDIS_PORT') ?: 6379,
28+
'password' => getenv('REDIS_PASSWORD') ?: null,
29+
'database' => getenv('REDIS_DATABASE') ?: 0,
30+
];
31+
32+
$adapter = new RedisAdapter($config);
33+
$registry = new CollectorRegistry($adapter, false);
34+
$format = new RenderTextFormat();
35+
$metrics = $registry->getMetricFamilySamples();
36+
$rendered = $format->render($metrics);
37+
38+
ob_start('ob_gzhandler');
39+
40+
header('Content-Type: ' . RenderTextFormat::MIME_TYPE);
41+
echo $rendered;
42+
43+
ob_end_flush();

0 commit comments

Comments
 (0)