-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Record metrics, Improve response times (#11)
* Improve response times * Fix linter errors * Measure request durations * Lint/format * Change logging format * Logging fix
- Loading branch information
Showing
21 changed files
with
220 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
[flake8] | ||
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist,.venv | ||
max-line-length = 120 | ||
extend-ignore = E203 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import socket | ||
from typing import Optional | ||
|
||
|
||
class SocketCacheMeta(type): | ||
__INSTANCE: dict[str, "SocketCache"] = dict() | ||
|
||
def __new__(cls, cls_name, cls_bases, cls_attrs): | ||
if cls_name not in cls.__INSTANCE: | ||
cls.__INSTANCE[cls_name] = type(cls_name, cls_bases, cls_attrs) | ||
return cls.__INSTANCE[cls_name] | ||
|
||
|
||
class SocketCache(metaclass=SocketCacheMeta): | ||
def __init__( | ||
self, | ||
) -> None: | ||
self.cache: dict[str, socket.socket] = dict() | ||
|
||
def put(self, server_addr: str, sock: socket.socket) -> None: | ||
self.cache[server_addr] = sock | ||
|
||
def get(self, server_addr: str) -> Optional[socket.socket]: | ||
return self.cache.get(server_addr) | ||
|
||
def delete(self, server_addr: str) -> None: | ||
if server_addr not in self.cache: | ||
return | ||
del self.cache[server_addr] | ||
|
||
|
||
socket_cache = SocketCache() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,24 @@ | ||
import socket | ||
from typing import Optional | ||
|
||
from optimus.logging.logger import log_error | ||
from optimus.networking.cache import socket_cache | ||
|
||
|
||
def query_server_over_udp(bin_data: bytearray, server_addr: str) -> bytes: | ||
""" | ||
Connects to given `server_addr` over UDP on port 53, sends given `bin_data` | ||
and returns back the response | ||
""" | ||
try: | ||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
sock.settimeout(3) | ||
sock.connect((server_addr, 53)) | ||
sock: Optional[socket.socket] = socket_cache.get(server_addr) | ||
if not sock: | ||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
sock.settimeout(5) | ||
sock.connect((server_addr, 53)) | ||
socket_cache.put(server_addr, sock) | ||
sock.send(bin_data) | ||
packet_bytes = sock.recv(600) # Read 600 bytes only for now | ||
packet_bytes = sock.recv(600) | ||
return packet_bytes | ||
except socket.timeout as texc: | ||
except socket.timeout: | ||
log_error(f"Error: Time out, couldn't complete lookup on {server_addr}") | ||
raise Exception("Socket Timeout Error") from texc | ||
except socket.error as err: | ||
return bytes() | ||
except socket.error: | ||
log_error(f"Error: Socket error while connecting to {server_addr}") | ||
raise Exception("Socket Error") from err | ||
finally: | ||
sock.shutdown(socket.SHUT_RDWR) | ||
sock.close() | ||
return bytes() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from prometheus_client import Counter, Histogram, start_http_server | ||
|
||
from optimus.logging.logger import log | ||
|
||
inbound_rqc = Counter("inbound_dns_requests", "Total Requests Received") | ||
served_rqc = Counter("served_dns_requests", "Total Requests Processed") | ||
erred_rqc = Counter("erred_dns_requests", "Total Requests Failed") | ||
|
||
req_duration_hist = Histogram("duration_dns_request", "Total time taken to process the request") | ||
|
||
PORT = 8000 | ||
|
||
|
||
def record_metrics(func): | ||
""" | ||
Requires a running Prometheus Metrics server | ||
TODO: Check whether Prometheus server is up and running on `PORT` | ||
""" | ||
|
||
@req_duration_hist.time() | ||
def wrapper(*args, **kwargs): | ||
inbound_rqc.inc(1) | ||
was_success: bool = func(*args, **kwargs) | ||
served_rqc.inc(1) | ||
if not was_success: | ||
erred_rqc.inc(1) | ||
|
||
return wrapper | ||
|
||
|
||
def with_prometheus_metrics_server(func): | ||
def wrapper(*args, **kwargs): | ||
start_http_server(PORT) | ||
log(f"Started Prometheus Server on Port {PORT}") | ||
func(*args, **kwargs) | ||
|
||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"servers": [ | ||
"198.41.0.4", | ||
"199.9.14.201", | ||
"192.33.4.12", | ||
"199.7.91.13", | ||
"192.203.230.10", | ||
"192.5.5.241", | ||
"192.112.36.4", | ||
"198.97.190.53", | ||
"192.36.148.17", | ||
"192.58.128.30", | ||
"193.0.14.129", | ||
"199.7.83.42", | ||
"202.12.27.33" | ||
] | ||
} | ||
|
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import json | ||
import os | ||
import pathlib | ||
import posixpath | ||
import socket | ||
from typing import List | ||
|
||
__NAMESERVERS: List[str] = [] | ||
|
||
|
||
def get_root_servers(): | ||
global __NAMESERVERS | ||
optimus_root = pathlib.Path(os.path.abspath(os.path.dirname(__file__))).parent | ||
if not __NAMESERVERS: | ||
file_path = os.path.join(optimus_root, "root_servers.json") | ||
if not posixpath.exists(file_path): | ||
raise Exception("root servers file not found !") | ||
with open(file_path, "r") as f: | ||
__NAMESERVERS = json.load(f)["servers"] | ||
return __NAMESERVERS | ||
|
||
|
||
def warmup_cache(cache): | ||
def inner(func): | ||
def wrapper(*args, **kwargs): | ||
addresses = get_root_servers() | ||
for addr in addresses: | ||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
sock.settimeout(5) | ||
sock.connect((addr, 53)) | ||
cache.put(addr, sock) | ||
func(*args, **kwargs) | ||
|
||
return wrapper | ||
|
||
return inner |
14 changes: 10 additions & 4 deletions
14
optimus/optimus_server/router.py → optimus/server/router.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
import socket | ||
from optimus.dns.models.packet import DNSPacket | ||
|
||
from optimus.dns.models.packet import DNSPacket, ResponseCode | ||
from optimus.dns.parser.parse import DNSParser | ||
from optimus.logging.logger import log | ||
from optimus.dns.resolver import resolve | ||
from optimus.logging.logger import log, log_error | ||
from optimus.prometheus import record_metrics | ||
|
||
|
||
def handle_request(master_socket: socket.socket, received_bytes: bytes, return_address: tuple[str, int]) -> None: | ||
@record_metrics | ||
def handle_request(master_socket: socket.socket, received_bytes: bytes, return_address: tuple[str, int]) -> bool: | ||
query_packet: DNSPacket = DNSParser(bytearray(received_bytes)).get_dns_packet() | ||
# TODO: Send query for each question in query_packet | ||
log(f"Received query for {query_packet.questions[0].name} TYPE {query_packet.questions[0].rtype}") | ||
response_packet: DNSPacket = resolve(query_packet) | ||
response_packet.header.is_recursion_available = True | ||
master_socket.sendto(response_packet.to_bin(), return_address) | ||
if response_packet.header.response_code != ResponseCode.NOERROR: | ||
log_error(f"Query for {query_packet.questions[0].name} TYPE {query_packet.questions[0].rtype} errored out") | ||
return False | ||
log(f"Query for {query_packet.questions[0].name} TYPE {query_packet.questions[0].rtype} successfully processed") | ||
return True |
Oops, something went wrong.