Performance Tips¶
- Use the context manager to ensure connections are closed promptly.
- For batch testing, use Python's
asyncioandasyncio.to_threadto parallelize checks (seetest.pyfor an example).
Asynchronous Usage for Performance¶
For best performance when testing many hosts, you can use CertMonitor in an asynchronous workflow. Below is a real-world example using Python's asyncio and CertMonitor's thread-safe context manager:
import asyncio
import json
import time
from certmonitor import CertMonitor
start_time = time.time()
total_time = 0
num_tests = 0
print_lock = asyncio.Lock()
async def test_certinfo_async(hostname, port: int = 443):
global total_time, num_tests
start = time.time()
validators = [
"subject_alt_names",
"weak_cipher",
"tls_version",
]
def run_certmonitor():
lines = []
with CertMonitor(host=hostname, port=port, enabled_validators=validators) as monitor:
lines.append(f"Testing {hostname}:{port}")
cert_details = monitor.get_cert_info()
lines.append(json.dumps(cert_details, indent=2))
verification_results = monitor.validate(
validator_args={
"subject_alt_names": [
"www.example.com",
"cisco.com",
"test.google.com",
"8.8.4.4",
"test.badssl.com",
]
}
)
lines.append(json.dumps(verification_results, indent=2))
cipher_info = monitor.get_cipher_info()
lines.append(json.dumps(cipher_info, indent=2))
return "\n".join(lines)
output = await asyncio.to_thread(run_certmonitor)
end = time.time()
elapsed = end - start
total_time += elapsed
num_tests += 1
chunk = "\n" + "=" * 50 + "\n" + f"{output}\n" + f"Test completed in {elapsed:.2f} seconds\n" + "=" * 50 + "\n"
async with print_lock:
print(chunk)
return elapsed
async def main():
hosts = [
("expired.badssl.com", 443),
("8.8.8.8", 443),
("example.com", 443),
("tls-v1-0.badssl.com", 1010),
("tls-v1-1.badssl.com", 1011),
("tls-v1-2.badssl.com", 1012),
]
tasks = [test_certinfo_async(host, port) for (host, port) in hosts]
for task in asyncio.as_completed(tasks):
try:
await task
except Exception as e:
async with print_lock:
print("\n" + "=" * 50 + "\n")
print(f"Test raised an exception: {e}")
print("=" * 50 + "\n")
if __name__ == "__main__":
asyncio.run(main())
end_time = time.time()
elapsed_time = end_time - start_time
average_time = total_time / num_tests if num_tests else 0
print(f"Elapsed time: {elapsed_time:.2f} seconds")
print(f"Average time per test: {average_time:.2f} seconds")
This approach allows you to efficiently test many hosts in parallel, maximizing throughput and minimizing total runtime.