mirror of
https://github.com/FlareSolverr/FlareSolverr.git
synced 2025-06-07 20:15:24 +00:00
Implement Prometheus metrics
This commit is contained in:
parent
313fb2c14b
commit
d2e144ea12
@ -56,6 +56,7 @@ COPY src .
|
|||||||
COPY package.json ../
|
COPY package.json ../
|
||||||
|
|
||||||
EXPOSE 8191
|
EXPOSE 8191
|
||||||
|
EXPOSE 8192
|
||||||
|
|
||||||
# dumb-init avoids zombie chromium processes
|
# dumb-init avoids zombie chromium processes
|
||||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||||
|
30
README.md
30
README.md
@ -227,7 +227,7 @@ This is the same as `request.get` but it takes one more param:
|
|||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
| Name | Default | Notes |
|
| Name | Default | Notes |
|
||||||
|-----------------|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| LOG_LEVEL | info | Verbosity of the logging. Use `LOG_LEVEL=debug` for more information. |
|
| LOG_LEVEL | info | Verbosity of the logging. Use `LOG_LEVEL=debug` for more information. |
|
||||||
| LOG_HTML | false | Only for debugging. If `true` all HTML that passes through the proxy will be logged to the console in `debug` level. |
|
| LOG_HTML | false | Only for debugging. If `true` all HTML that passes through the proxy will be logged to the console in `debug` level. |
|
||||||
| CAPTCHA_SOLVER | none | Captcha solving method. It is used when a captcha is encountered. See the Captcha Solvers section. |
|
| CAPTCHA_SOLVER | none | Captcha solving method. It is used when a captcha is encountered. See the Captcha Solvers section. |
|
||||||
@ -237,12 +237,40 @@ This is the same as `request.get` but it takes one more param:
|
|||||||
| TEST_URL | https://www.google.com | FlareSolverr makes a request on start to make sure the web browser is working. You can change that URL if it is blocked in your country. |
|
| TEST_URL | https://www.google.com | FlareSolverr makes a request on start to make sure the web browser is working. You can change that URL if it is blocked in your country. |
|
||||||
| PORT | 8191 | Listening port. You don't need to change this if you are running on Docker. |
|
| PORT | 8191 | Listening port. You don't need to change this if you are running on Docker. |
|
||||||
| HOST | 0.0.0.0 | Listening interface. You don't need to change this if you are running on Docker. |
|
| HOST | 0.0.0.0 | Listening interface. You don't need to change this if you are running on Docker. |
|
||||||
|
| PROMETHEUS_ENABLED | false | Enable Prometheus exporter. See the Prometheus section below. |
|
||||||
|
| PROMETHEUS_PORT | 8192 | Listening port for Prometheus exporter. See the Prometheus section below. |
|
||||||
|
|
||||||
Environment variables are set differently depending on the operating system. Some examples:
|
Environment variables are set differently depending on the operating system. Some examples:
|
||||||
* Docker: Take a look at the Docker section in this document. Environment variables can be set in the `docker-compose.yml` file or in the Docker CLI command.
|
* Docker: Take a look at the Docker section in this document. Environment variables can be set in the `docker-compose.yml` file or in the Docker CLI command.
|
||||||
* Linux: Run `export LOG_LEVEL=debug` and then start FlareSolverr in the same shell.
|
* Linux: Run `export LOG_LEVEL=debug` and then start FlareSolverr in the same shell.
|
||||||
* Windows: Open `cmd.exe`, run `set LOG_LEVEL=debug` and then start FlareSolverr in the same shell.
|
* Windows: Open `cmd.exe`, run `set LOG_LEVEL=debug` and then start FlareSolverr in the same shell.
|
||||||
|
|
||||||
|
## Prometheus exporter
|
||||||
|
|
||||||
|
The Prometheus exporter for FlareSolverr is disabled by default. It can be enabled with the environment variable `PROMETHEUS_ENABLED`. If you are using Docker make sure you expose the `PROMETHEUS_PORT`.
|
||||||
|
|
||||||
|
Example metrics:
|
||||||
|
```shell
|
||||||
|
# HELP flaresolverr_request_total Total requests with result
|
||||||
|
# TYPE flaresolverr_request_total counter
|
||||||
|
flaresolverr_request_total{domain="nowsecure.nl",result="solved"} 1.0
|
||||||
|
# HELP flaresolverr_request_created Total requests with result
|
||||||
|
# TYPE flaresolverr_request_created gauge
|
||||||
|
flaresolverr_request_created{domain="nowsecure.nl",result="solved"} 1.690141657157109e+09
|
||||||
|
# HELP flaresolverr_request_duration Request duration in seconds
|
||||||
|
# TYPE flaresolverr_request_duration histogram
|
||||||
|
flaresolverr_request_duration_bucket{domain="nowsecure.nl",le="0.0"} 0.0
|
||||||
|
flaresolverr_request_duration_bucket{domain="nowsecure.nl",le="10.0"} 1.0
|
||||||
|
flaresolverr_request_duration_bucket{domain="nowsecure.nl",le="25.0"} 1.0
|
||||||
|
flaresolverr_request_duration_bucket{domain="nowsecure.nl",le="50.0"} 1.0
|
||||||
|
flaresolverr_request_duration_bucket{domain="nowsecure.nl",le="+Inf"} 1.0
|
||||||
|
flaresolverr_request_duration_count{domain="nowsecure.nl"} 1.0
|
||||||
|
flaresolverr_request_duration_sum{domain="nowsecure.nl"} 5.858
|
||||||
|
# HELP flaresolverr_request_duration_created Request duration in seconds
|
||||||
|
# TYPE flaresolverr_request_duration_created gauge
|
||||||
|
flaresolverr_request_duration_created{domain="nowsecure.nl"} 1.6901416571570296e+09
|
||||||
|
```
|
||||||
|
|
||||||
## Captcha Solvers
|
## Captcha Solvers
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
|
@ -2,9 +2,10 @@ bottle==0.12.25
|
|||||||
waitress==2.1.2
|
waitress==2.1.2
|
||||||
selenium==4.10.0
|
selenium==4.10.0
|
||||||
func-timeout==4.3.5
|
func-timeout==4.3.5
|
||||||
|
prometheus-client==0.17.1
|
||||||
# required by undetected_chromedriver
|
# required by undetected_chromedriver
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
certifi==2023.5.7
|
certifi==2023.7.22
|
||||||
websockets==11.0.3
|
websockets==11.0.3
|
||||||
# only required for linux
|
# only required for linux
|
||||||
xvfbwrapper==0.2.9
|
xvfbwrapper==0.2.9
|
||||||
|
53
src/bottle_plugins/prometheus_plugin.py
Normal file
53
src/bottle_plugins/prometheus_plugin.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
from dtos import V1ResponseBase
|
||||||
|
from metrics import start_metrics_http_server, REQUEST_COUNTER, REQUEST_DURATION
|
||||||
|
|
||||||
|
PROMETHEUS_ENABLED = os.environ.get('PROMETHEUS_ENABLED', 'false').lower() == 'true'
|
||||||
|
PROMETHEUS_PORT = int(os.environ.get('PROMETHEUS_PORT', 8192))
|
||||||
|
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
if PROMETHEUS_ENABLED:
|
||||||
|
start_metrics_http_server(PROMETHEUS_PORT)
|
||||||
|
|
||||||
|
|
||||||
|
def prometheus_plugin(callback):
|
||||||
|
"""
|
||||||
|
Bottle plugin to expose Prometheus metrics
|
||||||
|
http://bottlepy.org/docs/dev/plugindev.html
|
||||||
|
"""
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
actual_response = callback(*args, **kwargs)
|
||||||
|
|
||||||
|
if PROMETHEUS_ENABLED:
|
||||||
|
try:
|
||||||
|
export_metrics(actual_response)
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning("Error exporting metrics: " + str(e))
|
||||||
|
|
||||||
|
return actual_response
|
||||||
|
|
||||||
|
def export_metrics(actual_response):
|
||||||
|
res = V1ResponseBase(actual_response)
|
||||||
|
|
||||||
|
domain = "unknown"
|
||||||
|
if res.solution and res.solution.url:
|
||||||
|
parsed_url = urllib.parse.urlparse(res.solution.url)
|
||||||
|
domain = parsed_url.hostname
|
||||||
|
|
||||||
|
run_time = (res.endTimestamp - res.startTimestamp) / 1000
|
||||||
|
REQUEST_DURATION.labels(domain=domain).observe(run_time)
|
||||||
|
|
||||||
|
result = "unknown"
|
||||||
|
if res.message == "Challenge solved!":
|
||||||
|
result = "solved"
|
||||||
|
elif res.message == "Challenge not detected!":
|
||||||
|
result = "not_detected"
|
||||||
|
elif res.message.startswith("Error"):
|
||||||
|
result = "error"
|
||||||
|
REQUEST_COUNTER.labels(domain=domain, result=result).inc()
|
||||||
|
|
||||||
|
return wrapper
|
@ -8,6 +8,7 @@ from bottle import run, response, Bottle, request, ServerAdapter
|
|||||||
|
|
||||||
from bottle_plugins.error_plugin import error_plugin
|
from bottle_plugins.error_plugin import error_plugin
|
||||||
from bottle_plugins.logger_plugin import logger_plugin
|
from bottle_plugins.logger_plugin import logger_plugin
|
||||||
|
from bottle_plugins import prometheus_plugin
|
||||||
from dtos import V1RequestBase
|
from dtos import V1RequestBase
|
||||||
import flaresolverr_service
|
import flaresolverr_service
|
||||||
import utils
|
import utils
|
||||||
@ -24,10 +25,6 @@ class JSONErrorBottle(Bottle):
|
|||||||
|
|
||||||
app = JSONErrorBottle()
|
app = JSONErrorBottle()
|
||||||
|
|
||||||
# plugin order is important
|
|
||||||
app.install(logger_plugin)
|
|
||||||
app.install(error_plugin)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@ -101,6 +98,13 @@ if __name__ == "__main__":
|
|||||||
# test browser installation
|
# test browser installation
|
||||||
flaresolverr_service.test_browser_installation()
|
flaresolverr_service.test_browser_installation()
|
||||||
|
|
||||||
|
# start bootle plugins
|
||||||
|
# plugin order is important
|
||||||
|
app.install(logger_plugin)
|
||||||
|
app.install(error_plugin)
|
||||||
|
prometheus_plugin.setup()
|
||||||
|
app.install(prometheus_plugin.prometheus_plugin)
|
||||||
|
|
||||||
# start webserver
|
# start webserver
|
||||||
# default server 'wsgiref' does not support concurrent requests
|
# default server 'wsgiref' does not support concurrent requests
|
||||||
# https://github.com/FlareSolverr/FlareSolverr/issues/680
|
# https://github.com/FlareSolverr/FlareSolverr/issues/680
|
||||||
|
32
src/metrics.py
Normal file
32
src/metrics.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from prometheus_client import Counter, Histogram, start_http_server
|
||||||
|
import time
|
||||||
|
|
||||||
|
REQUEST_COUNTER = Counter(
|
||||||
|
name='flaresolverr_request',
|
||||||
|
documentation='Total requests with result',
|
||||||
|
labelnames=['domain', 'result']
|
||||||
|
)
|
||||||
|
REQUEST_DURATION = Histogram(
|
||||||
|
name='flaresolverr_request_duration',
|
||||||
|
documentation='Request duration in seconds',
|
||||||
|
labelnames=['domain'],
|
||||||
|
buckets=[0, 10, 25, 50]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def serve(port):
|
||||||
|
start_http_server(port=port)
|
||||||
|
while True:
|
||||||
|
time.sleep(600)
|
||||||
|
|
||||||
|
|
||||||
|
def start_metrics_http_server(prometheus_port: int):
|
||||||
|
logging.info(f"Serving Prometheus exporter on http://0.0.0.0:{prometheus_port}/metrics")
|
||||||
|
from threading import Thread
|
||||||
|
Thread(
|
||||||
|
target=serve,
|
||||||
|
kwargs=dict(port=prometheus_port),
|
||||||
|
daemon=True,
|
||||||
|
).start()
|
Loading…
x
Reference in New Issue
Block a user