Skip to content
This repository was archived by the owner on Sep 26, 2022. It is now read-only.

Commit d2564d9

Browse files
authored
Merge pull request #237 from sr-gi/fix-log-port
Lets the OS pick a free port instead of harcoding one
2 parents 4f2ad7c + 5122378 commit d2564d9

File tree

5 files changed

+46
-21
lines changed

5 files changed

+46
-21
lines changed

teos/api.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def get_request_data_json(request):
5959
raise InvalidParameter("Request is not json encoded")
6060

6161

62-
def serve(internal_api_endpoint, endpoint, min_to_self_delay, auto_run=False):
62+
def serve(internal_api_endpoint, endpoint, logging_port, min_to_self_delay, auto_run=False):
6363
"""
6464
Starts the API.
6565
@@ -68,6 +68,7 @@ def serve(internal_api_endpoint, endpoint, min_to_self_delay, auto_run=False):
6868
Args:
6969
internal_api_endpoint (:obj:`str`): endpoint where the internal api is running (``host:port``).
7070
endpoint (:obj:`str`): endpoint where the http api will be running (``host:port``).
71+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
7172
min_to_self_delay (:obj:`str`): the minimum to_self_delay accepted by the :obj:`Inspector`.
7273
auto_run (:obj:`bool`): whether the server should be started by this process. False if run with an external
7374
WSGI. True is run by Flask.
@@ -76,7 +77,7 @@ def serve(internal_api_endpoint, endpoint, min_to_self_delay, auto_run=False):
7677
The application object needed by the WSGI server to run if ``auto_run`` is False, :obj:`None` otherwise.
7778
"""
7879

79-
setup_logging()
80+
setup_logging(logging_port)
8081
inspector = Inspector(int(min_to_self_delay))
8182
api = API(inspector, internal_api_endpoint)
8283

teos/constants.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging.handlers
22

33
SHUTDOWN_GRACE_TIME = 10 # Grace time in seconds to complete any pending call when stopping one of the services of TEOS
4-
TCP_LOGGING_PORT = logging.handlers.DEFAULT_TCP_LOGGING_PORT # The port used for the tcp logging service is 9020
54
OUTDATED_USERS_CACHE_SIZE_BLOCKS = 10 # Size of the users cache, in blocks

teos/logger.py

+20-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from io import StringIO
1212

1313
from teos.tools import ignore_signal
14-
from teos.constants import TCP_LOGGING_PORT
1514

1615
configured = False # set to True once setup_logging is called
1716

@@ -31,10 +30,13 @@ def makeRecord(self, *args, **kwargs):
3130
return rv
3231

3332

34-
def setup_logging():
33+
def setup_logging(logging_port):
3534
"""
3635
Configures the logging options. It must be called only once, before using get_logger.
3736
37+
Args:
38+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
39+
3840
Raises:
3941
:obj:`RuntimeError`: if ``setup_logging`` had already been called.
4042
"""
@@ -56,7 +58,7 @@ def setup_logging():
5658
"level": "DEBUG",
5759
"class": "logging.handlers.SocketHandler",
5860
"host": "localhost",
59-
"port": TCP_LOGGING_PORT,
61+
"port": logging_port,
6062
"filters": ["onlyteos"],
6163
},
6264
},
@@ -179,11 +181,19 @@ def handle_log_record(record):
179181

180182

181183
class LogRecordSocketReceiver(socketserver.ThreadingTCPServer):
182-
"""Simple TCP socket-based logging receiver."""
184+
"""
185+
Simple TCP socket-based logging receiver.
186+
187+
Args:
188+
host (:obj:`str`): the hostname or ip where the logging server can be reached. Defaults to localhost.
189+
port (:obj:`int`): the port where the logging server can be reached. Defaults to 0 so the OS can pick a free
190+
one.
191+
handler (:obj:`StreamRequestHandler`): the log handler.
192+
"""
183193

184194
allow_reuse_address = True
185195

186-
def __init__(self, host="localhost", port=TCP_LOGGING_PORT, handler=LogRecordStreamHandler):
196+
def __init__(self, host="localhost", port=0, handler=LogRecordStreamHandler):
187197
socketserver.ThreadingTCPServer.__init__(self, (host, port), handler)
188198
self.timeout = 1
189199

@@ -196,13 +206,14 @@ def serve_forever(self, poll_interval=0.5):
196206
self.handle_request()
197207

198208

199-
def serve(log_file_path, silent, ready):
209+
def serve(log_file_path, logging_port, silent, ready):
200210
"""
201-
Sets up logging on console and file, and serves the tcp logging server on ``localhost:TCP_LOGGING_PORT``.
211+
Sets up logging on console and file, and serves the tcp logging server on ``localhost:tcp_logging_port``.
202212
This method is meant to be run in a separate process and provides the logging service.
203213
204214
Args:
205215
log_file_path (:obj:`str`): the full path and log file name.
216+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
206217
silent (:obj:`bool`): if True, only ``CRITICAL`` errors are shown to console; otherwise ``INFO`` and above.
207218
ready (:obj:`multiprocessing.Event`): an event that is set once the logging server is ready.
208219
"""
@@ -222,6 +233,7 @@ def serve(log_file_path, silent, ready):
222233
# Ignore SIGINT so this process does not crash on CTRL+C, but comply on other signals
223234
signal(SIGINT, ignore_signal)
224235

225-
tcpserver = LogRecordSocketReceiver()
236+
tcpserver = LogRecordSocketReceiver(port=logging_port.value)
237+
logging_port.value = tcpserver.server_address[1]
226238
ready.set()
227239
tcpserver.serve_forever()

teos/rpc.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def stop(self, request, context):
9999
return self.stub.stop(request)
100100

101101

102-
def serve(rpc_bind, rpc_port, internal_api_endpoint, stop_event):
102+
def serve(rpc_bind, rpc_port, internal_api_endpoint, logging_port, stop_event):
103103
"""
104104
Serves the external RPC API at the given endpoint and connects it to the internal api.
105105
@@ -109,11 +109,12 @@ def serve(rpc_bind, rpc_port, internal_api_endpoint, stop_event):
109109
rpc_bind (:obj:`str`): the IP or host where the RPC server will be hosted.
110110
rpc_port (:obj:`int`): the port where the RPC server will be hosted.
111111
internal_api_endpoint (:obj:`str`): the endpoint where to reach the internal (gRPC) api.
112+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
112113
stop_event (:obj:`multiprocessing.Event`) the Event that this service will monitor. The rpc server will
113114
initiate a graceful shutdown once this event is set.
114115
"""
115116

116-
setup_logging()
117+
setup_logging(logging_port)
117118
rpc = RPC(rpc_bind, rpc_port, internal_api_endpoint)
118119
# Ignores SIGINT so the main process can handle the teardown
119120
signal(SIGINT, ignore_signal)

teos/teosd.py

+20-8
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class TeosDaemon:
6464
config (:obj:`dict`): the configuration object.
6565
sk (:obj:`PrivateKey`): the :obj:`PrivateKey` of the tower.
6666
logger (:obj:`Logger <teos.logger.Logger>`): the logger instance.
67+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
6768
6869
Attributes:
6970
stop_command_event (:obj:`threading.Event`): The event that will be set to initiate a graceful shutdown.
@@ -85,9 +86,10 @@ class TeosDaemon:
8586
rpc_process (:obj:`multiprocessing.Process`): The instance of the internal RPC server; only set if running.
8687
"""
8788

88-
def __init__(self, config, sk, logger):
89+
def __init__(self, config, sk, logger, logging_port):
8990
self.config = config
9091
self.logger = logger
92+
self.logging_port = logging_port
9193

9294
# event triggered when a ``stop`` command is issued
9395
# Using multiprocessing.Event seems to cause a deadlock if event.set() is called in a signal handler that
@@ -153,6 +155,7 @@ def __init__(self, config, sk, logger):
153155
self.config.get("RPC_BIND"),
154156
self.config.get("RPC_PORT"),
155157
self.internal_api_endpoint,
158+
self.logging_port,
156159
self.stop_event,
157160
),
158161
daemon=True,
@@ -238,8 +241,14 @@ def bootstrap_components(self):
238241
# Activate ChainMonitor
239242
self.chain_monitor.activate()
240243

241-
def start_services(self):
242-
"""Readies the tower by setting up signal handling, and starting all the services."""
244+
def start_services(self, logging_port):
245+
"""
246+
Readies the tower by setting up signal handling, and starting all the services.
247+
248+
Args:
249+
logging_port (:obj:`int`): the port where the logging server can be reached (localhost:logging_port)
250+
"""
251+
243252
signal(SIGINT, self.handle_signals)
244253
signal(SIGTERM, self.handle_signals)
245254
signal(SIGQUIT, self.handle_signals)
@@ -262,7 +271,8 @@ def start_services(self):
262271
"gunicorn",
263272
f"--bind={api_endpoint}",
264273
f"teos.api:serve(internal_api_endpoint='{self.internal_api_endpoint}', "
265-
f"endpoint='{api_endpoint}', min_to_self_delay='{self.config.get('MIN_TO_SELF_DELAY')}')",
274+
f"endpoint='{api_endpoint}', logging_port='{logging_port}', "
275+
f"min_to_self_delay='{self.config.get('MIN_TO_SELF_DELAY')}')",
266276
]
267277
)
268278
else:
@@ -271,6 +281,7 @@ def start_services(self):
271281
kwargs={
272282
"internal_api_endpoint": self.internal_api_endpoint,
273283
"endpoint": api_endpoint,
284+
"logging_port": logging_port,
274285
"min_to_self_delay": self.config.get("MIN_TO_SELF_DELAY"),
275286
"auto_run": True,
276287
},
@@ -326,7 +337,7 @@ def start(self):
326337
"""This method implements the whole lifetime cycle of the the TEOS tower. This method does not return."""
327338
self.logger.info("Starting TEOS")
328339
self.bootstrap_components()
329-
self.start_services()
340+
self.start_services(self.logging_port)
330341

331342
self.stop_command_event.wait()
332343

@@ -338,14 +349,15 @@ def main(config):
338349

339350
silent = config.get("DAEMON")
340351
logging_server_ready = multiprocessing.Event()
352+
logging_port = multiprocessing.Value("i")
341353
logging_process = multiprocessing.Process(
342-
target=serve_logging, daemon=True, args=(config.get("LOG_FILE"), silent, logging_server_ready)
354+
target=serve_logging, daemon=True, args=(config.get("LOG_FILE"), logging_port, silent, logging_server_ready)
343355
)
344356
logging_process.start()
345357

346358
logging_server_ready.wait()
347359

348-
setup_logging()
360+
setup_logging(logging_port.value)
349361
logger = get_logger(component="Daemon")
350362

351363
if not os.path.exists(config.get("TEOS_SECRET_KEY")) or config.get("OVERWRITE_KEY"):
@@ -366,7 +378,7 @@ def main(config):
366378
logger.warning("Windows cannot run gunicorn as WSGI. Changing to waitress")
367379

368380
try:
369-
TeosDaemon(config, sk, logger).start()
381+
TeosDaemon(config, sk, logger, logging_port.value).start()
370382
except Exception as e:
371383
logger.error("An error occurred: {}. Shutting down".format(e))
372384
exit(1)

0 commit comments

Comments
 (0)