Skip to content

Commit

Permalink
feat: adds env var LOG_LEVEL and detailed README.md (#21)
Browse files Browse the repository at this point in the history
* adds detailed documentation

* move metrics to /metrics to respect the standard

* implements env var setting LOG_LEVEL

* minor changes to README
  • Loading branch information
schaermu authored Apr 15, 2024
1 parent d5f3303 commit 487524e
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 13 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"ltex.language": "en"
}
106 changes: 102 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,103 @@
# changedetection.io Prometheus Exporter
# Changedetection.io Prometheus Exporter
This application exports the latest prices of watches configured inside a [changedetection.io](https://changedetection.io) instance as prometheus-compatible metrics. Additionally, the exporter exposes metrics regarding scraping statistics and certain system information in order to enable system monitoring as well.

## Building
### Note on docker multi-platform builds
docker buildx create --name multi-builder --bootstrap --use
- Exposes price metrics for eligible watches (must be of type @Offer).
- Exposes scrape metrics to monitor performance of your watches.
- Monitor instance metrics like queue size, uptime or overdue watches.
- Visualize watches with the same name (but different sources) to compare price developments.

Right now, there are no plans for further development (maybe an example Grafana dashboard at some point in time). If you feel something is missing, feel free to open up an issue or (even better) a pull request!

## Installation
The recommended way to run the exporter is as a part of your docker-compose stack or as a pod on your k8s cluster. Of course, you can also run it directly as a binary on your host, you have to manually compile this one yourself though.

### Docker (with docker-compose)
```yaml
services:
changedection-exporter:
image: ghcr.io/schaermu/changedetection.io-exporter:latest
container_name: changedetection-exporter
restart: unless-stopped
environment:
- CDIO_API_BASE_URL=http://changedetection:5000
- CDIO_API_KEY=...
depends_on:
changedetection:
condition: service_started
```
This example assumes that you have started an instance of changedetection.io within the same docker network reachable via hostname `changedetection` and didn't change the default port of 5000.

### Kubernetes (tbd)
```
```
The exporter is configured using the following environment variables:
|Environment Variable|Default value|Mandatory?|
|---|---|---|
|`CDIO_API_BASE_URL`|-|yes|
|`CDIO_API_KEY`|-|yes|
|`PORT`|`9123`|no|
|`LOG_LEVEL`|`info`|no|
For all scenarios, setting both the `CDIO_API_BASE_URL` and a `CDIO_API_KEY` environment variable is mandatory, and the exporter will panic on startup if any of those is missing.
## Usage
Metrics can be access by requesting the path `/metrics` using the exporter's hostname and its configured port (or the default one of 9123).
If you want to read those metrics into Prometheus or VictoriaMetrics, you have to configure a scraper like this:
```yml
scrape_configs:
- job_name: "changedetection"
static_configs:
- targets: ["changedetection-exporter:9123"]
```
If you haven't got any watches registered on your changedetection.io instance, you will simply get the system metrics read in:
|Metric name|Labels|Type|
|---|---|---|
|`changedetectionio_system_uptime`|`version`|Gauge|
|`changedetectionio_system_watch_count`|`version`|Gauge|
|`changedetectionio_system_overdue_watch_count`|`version`|Gauge|
|`changedetectionio_system_queue_size`|`version`|Gauge|

The label `version` contains the running version of changedetection.io (i.e. 0.45.6).

If you have any watches registered, you will additionally get the following metrics for each of those:
|Metric name|Labels|Type|
|---|---|---|
|`changedetectionio_watch_check_count`|`title`,`source`|Counter|
|`changedetectionio_watch_fetch_time`|`title`,`source`|Gauge|
|`changedetectionio_watch_notification_alert_count`|`title`,`source`|Counter|
|`changedetectionio_watch_last_check_status`|`title`,`source`|Gauge|
|`changedetectionio_watch_price`|`title`,`source`|Gauge|

**IMPORTANT**: the metric `changedetectionio_watch_price` will ONLY be exposed for watches that return price information in the shape of a JSON object (with the attribute `@type` set to `Offer`).

The label `title` should be pretty self-explanatory, it simply contains the title from changedetection.io. In order to make sure all those metrics are unique, an additional label `source` is being exported. It contains the **host-part** of the monitored URL (i.e. www.foobar.org, so including the subdomain).

## Contributing
There are two ways you can build and run the exporter locally: using the binary build or a docker image. For both options, there are `Makefile` targets:
```bash
# clean artifacts, run tests and build binary
$ make

# clean artifacts, compile and run binary
$ make run

# create a docker image (see note below)
$ make docker
```

**IMPORTANT**: before running the docker build, you have to bootstrap the multi-platform build system in docker by running `docker buildx create --name multi-builder --bootstrap --use`.

To run the tests, you can leverage `Makefile` targets as well:
```bash
# run tests
$ make tests

# run tests with code coverage output (coverage.html)
$ make cover

# run tests in watch mode to re-run on all code-changes
$ make watch
```
28 changes: 20 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,34 @@ import (
log "github.com/sirupsen/logrus"
)

var (
port = os.Getenv("PORT")
logLevel = os.Getenv("LOG_LEVEL")
apiUrl = os.Getenv("CDIO_API_BASE_URL")
apiKey = os.Getenv("CDIO_API_KEY")
)

func init() {
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05.000000",
})

log.SetLevel(log.DebugLevel)
switch logLevel {
case "debug":
log.SetLevel(log.DebugLevel)
case "warn":
log.SetLevel(log.WarnLevel)
case "error":
log.SetLevel(log.ErrorLevel)
case "fatal":
log.SetLevel(log.FatalLevel)
default:
log.SetLevel(log.InfoLevel)
}
}

func main() {
var (
port = os.Getenv("PORT")
apiUrl = os.Getenv("CDIO_API_BASE_URL")
apiKey = os.Getenv("CDIO_API_KEY")
)

if port == "" {
port = "9123"
}
Expand All @@ -59,7 +71,7 @@ func main() {
)

// register prometheus handler
http.Handle("/", promhttp.HandlerFor(registry, promhttp.HandlerOpts{
http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{
ErrorLog: log.StandardLogger(),
}))
log.Info(fmt.Sprintf("Beginning to serve on port %s", port))
Expand Down
2 changes: 1 addition & 1 deletion pkg/collectors/watch_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
"changedetectionio_watch_check_count",
"changedetectionio_watch_fetch_time",
"changedetectionio_watch_notification_alert_count",
"changedetectionio_watch__last_check_status",
"changedetectionio_watch_last_check_status",
}
)

Expand Down

0 comments on commit 487524e

Please sign in to comment.