I have this tcpserver.py
class Server(TCPServer):
allow_reuse_address = True
# The constant would be better initialized by a systemd module
SYSTEMD_FIRST_SOCKET_FD = 3
def __init__(self, server_address, handler_cls, bind_and_activate=True):
self.handlers = set()
# Invoke base but omit bind/listen steps (performed by systemd activation!)
try:
TCPServer.__init__(self, server_address, handler_cls, bind_and_activate)
except TypeError:
TCPServer.__init__(self, server_address, handler_cls)
# Override socket
self.socket = socket.fromfd(
self.SYSTEMD_FIRST_SOCKET_FD, self.address_family, self.socket_type)
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
def server_close(self):
TCPServer.server_close(self)
_LOG.debug("Shutting down server.")
for handler in self.handlers.copy():
self.shutdown_request(handler.request)
def main():
""" Starts TCPServer.
"""
logging.basicConfig(level=logging.DEBUG)
server = ("", int(TCP_PORT))
# Create a TCP Server instance
server = Server(server, TCPServerRequestHandler)
try:
server.serve_forever()
except KeyboardInterrupt:
sys.exit(0)
then I made request_handler.py:
from prometheus_client import start_http_server, Gauge, Counter, Histogram
# Define Prometheus metrics
client_connections = Gauge('tcp_server_client_connections', 'Number of client connections')
client_names = Gauge('tcp_server_client_names', 'Names of connected clients', labelnames=['client'])
class TCPServerRequestHandler(RequestHandler):
def handle(self):
"""Receives data from client.
"""
start_time = time.time()
msg = self.request.recv(1024).strip()
if self.client_address and not msg:
_LOG.error("No Data revieved from Client: {}".format(self.client_address[0]))
return
client_address = self.client_address[0]
decoded_msg = msg.decode('utf-8')
client_connections.inc()
client_names.labels(client=client_address).set(1)
try:
data = ast.literal_eval(decoded_msg)
except ValueError:
data = decoded_msg
if data and isinstance(data, dict):
_LOG.debug("Data received is a dict.")
# TODO: Action to perform.
_type = 'dictionary'
elif isinstance(data, str):
_LOG.debug("str Data recieved.")
_type = 'string'
else:
_LOG.error("No data recieved.")
time_taken = time.time() - start_time
connection_duration.observe(time_taken)
self.request.sendall(f"Acknowledged data received of type {_type} and took {time_taken} to process".encode())
def main():
# Start Prometheus HTTP server on port 8000
start_http_server(8035)
and just calling the main function above the Prometheus http server doesn't start. So I went back to this three step demo https://github.com/prometheus/client_python/blob/master/docs/content/getting-started/three-step-demo.md
I spotted that after it starts the HTTP server: start_http_server(8000) it uses while loop and call the function inside that while loop!
which I tested and works as given in the example given in the three step demo.
So my question is: does that mean I would have to call the
server = Server(server, TCPServerRequestHandler)
server.serve_forever()
inside the while block of tcpserver.py
I was hoping to keep the exporter and tcpserver separate!