1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
"""Prometheus exporter for Apache Traffic Server's stats_over_http plugin."""
import argparse
import logging
import sys
from os import path
from prometheus_client import REGISTRY, ProcessCollector
from .collector import StatsPluginCollector
from .http import start_http_server
PKG_METRICS_FILE = path.join(
path.dirname(sys.modules["trafficserver_exporter"].__file__), "metrics.yaml"
)
ARGS = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description="Traffic Server exporter for Prometheus",
)
ARGS.add_argument(
"--endpoint",
dest="endpoint",
default="http://127.0.0.1/_stats",
help="Traffic Server's stats_over_http plugin URL",
)
ARGS.add_argument(
"--metrics-file",
dest="metrics_file",
default=PKG_METRICS_FILE,
help="YAML file containing the metrics definition",
)
ARGS.add_argument(
"--addr", dest="addr", default="", help="Address to bind and listen on"
)
ARGS.add_argument(
"--port", dest="port", default=9122, type=int, help="Port to bind and listen on"
)
ARGS.add_argument(
"--pidfile",
dest="pidfile",
default="/var/run/trafficserver/server.lock",
help="Path to trafficserver PID file; used with --procstats",
)
ARGS.add_argument(
"--procstats",
dest="procstats",
action="store_true",
help="Enable process metric collection",
)
ARGS.add_argument(
"--no-procstats",
dest="procstats",
action="store_false",
help="Disable process metric collection",
)
ARGS.set_defaults(procstats=True)
ARGS.add_argument(
"--no-ssl-verification",
dest="sslverification",
action="store_false",
help="Disable SSL certificate verification on metric collection",
)
ARGS.set_defaults(sslverification=True)
ARGS.add_argument(
"--max-retries",
dest="max_retries",
type=int,
default=0,
help="Maximum retries for DNS lookups or connnection timeouts/failures",
)
ARGS.add_argument(
"-v",
"--verbose",
action="count",
dest="level",
default=0,
help="Verbose logging (repeat for more verbosity)",
)
LOG = logging.getLogger(__name__)
def get_ts_pid(pidfile):
"""Read a pidfile, return a PID."""
try:
with open(pidfile) as f:
pid = f.readline()
except EnvironmentError:
LOG.warning("Unable to read pidfile; process metrics will fail!")
pid = None
return pid
def main():
"""Main program.
Parse arguments, start webserver to serve /metrics.
"""
args = ARGS.parse_args()
if args.level >= 2:
logging.basicConfig(level=logging.DEBUG)
elif args.level == 1:
logging.basicConfig(level=logging.INFO)
elif args.level == 0:
logging.basicConfig(level=logging.WARNING)
LOG.debug("Starting HTTP server")
httpd_thread = start_http_server(args.port, addr=args.addr)
LOG.debug("Registering StatsPluginCollector")
REGISTRY.register(
StatsPluginCollector(
args.endpoint,
args.metrics_file,
max_retries=args.max_retries,
ssl_verify=args.sslverification,
)
)
if args.procstats:
LOG.debug("Registering ProcessCollector")
REGISTRY.register(
ProcessCollector(
pid=lambda: get_ts_pid(args.pidfile), namespace="trafficserver"
)
)
LOG.info("Listening on :{port}".format(port=args.port))
# Wait for the webserver
httpd_thread.join()
|