82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
|
import time
|
||
|
|
||
|
import prometheus_client
|
||
|
from prometheus_client import start_http_server, Gauge, Counter
|
||
|
import sys
|
||
|
import argparse
|
||
|
import os
|
||
|
import stat
|
||
|
from http.server import HTTPServer
|
||
|
|
||
|
prometheus_client.REGISTRY.unregister(prometheus_client.GC_COLLECTOR)
|
||
|
prometheus_client.REGISTRY.unregister(prometheus_client.PLATFORM_COLLECTOR)
|
||
|
prometheus_client.REGISTRY.unregister(prometheus_client.PROCESS_COLLECTOR)
|
||
|
|
||
|
# Create a metric to track time spent and requests made.
|
||
|
FILE_TIME = Gauge("file_time_seconds", "File last modification time", labelnames=['path', 'type'])
|
||
|
FILE_SIZE = Gauge("file_size", "File size in bytes", labelnames=['path', 'type'])
|
||
|
|
||
|
|
||
|
class Handler(prometheus_client.MetricsHandler):
|
||
|
def do_GET(self) -> None:
|
||
|
for file in FILES.keys():
|
||
|
type = FILES[file]
|
||
|
try:
|
||
|
FILE_TIME.labels(file, type).set(0)
|
||
|
FILE_SIZE.labels(file, type).set(0)
|
||
|
# follow symlinks
|
||
|
stats = os.stat(path=file)
|
||
|
if stat.S_ISREG(stats.st_mode):
|
||
|
FILE_TIME.labels(file, type).set(stats.st_mtime)
|
||
|
FILE_SIZE.labels(file, type).set(stats.st_size)
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
return super().do_GET()
|
||
|
|
||
|
|
||
|
# map of filename to type
|
||
|
FILES = {}
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
DEFAULT_PORT = 8080
|
||
|
parser = argparse.ArgumentParser(prog=sys.argv[0],
|
||
|
description=f"""Statistics on a (backup) file,
|
||
|
|
||
|
Usage: ${sys.argv[0]} [-p|--port <port>] <label1>:<filepath1> .... <labeln>:<filepathn>
|
||
|
|
||
|
Listens on port {DEFAULT_PORT} by default. It exposes statistics
|
||
|
on the monitored files to prometheus. Current metrics are
|
||
|
|
||
|
{FILE_TIME._name}{{path="/path/to/file"}}: file modification time in seconds since 1970
|
||
|
{FILE_SIZE._name}{{path="/path/to/file"}}: file size in bytes
|
||
|
|
||
|
If a path does not exist or is not a regular file then the value 0 is returned.
|
||
|
The exporter follow symlinks.
|
||
|
|
||
|
The synax of each file is fo theform <label>:<file> where <label> is the value of
|
||
|
the type label in the prometheus export.
|
||
|
|
||
|
""",
|
||
|
epilog="Have a lot of fun!",
|
||
|
formatter_class=argparse.RawTextHelpFormatter)
|
||
|
parser.add_argument("files", nargs="*", help="Files to monitor")
|
||
|
parser.add_argument("-p", "--port", type=int, default=DEFAULT_PORT, help="Port to listen on")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
filespecs = args.files
|
||
|
for filespec in filespecs:
|
||
|
ind = filespec.index(":")
|
||
|
fname = filespec[ind+1:]
|
||
|
label= filespec[:ind]
|
||
|
FILES[fname] = label
|
||
|
|
||
|
|
||
|
PORT = args.port
|
||
|
|
||
|
print(f"Monitoring files {FILES}")
|
||
|
# Start up the server to expose the metrics.
|
||
|
print(f"Listening on port {PORT}")
|
||
|
|
||
|
HTTPServer(('0.0.0.0', PORT), Handler).serve_forever()
|