Skip to content

Commit af9bb59

Browse files
committed
Adds rich formatting of logs and updates the default logging styles.
Additionally, `matlab-proxy-app-list-servers` renders the output as a table, and now supports a `--quiet | -q` flag to only print links to running servers.
1 parent 598f656 commit af9bb59

File tree

11 files changed

+262
-146
lines changed

11 files changed

+262
-146
lines changed

matlab_proxy/app.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ def configure_no_proxy_in_env():
996996
os.environ["no_proxy"] = ",".join(
997997
set(existing_no_proxy_env + no_proxy_whitelist)
998998
)
999-
logger.info(f"Setting no_proxy to: {os.environ.get('no_proxy')}")
999+
logger.debug(f"Setting no_proxy to: {os.environ.get('no_proxy')}")
10001000

10011001

10021002
def create_and_start_app(config_name):
@@ -1053,12 +1053,12 @@ def print_version_and_exit():
10531053

10541054
def main():
10551055
"""Starting point of the integration. Creates the web app and runs indefinitely."""
1056-
if util.parse_cli_args()["version"]:
1056+
if util.parse_main_cli_args()["version"]:
10571057
print_version_and_exit()
10581058

10591059
# The integration needs to be called with --config flag.
10601060
# Parse the passed cli arguments.
1061-
desired_configuration_name = util.parse_cli_args()["config"]
1061+
desired_configuration_name = util.parse_main_cli_args()["config"]
10621062

10631063
create_and_start_app(config_name=desired_configuration_name)
10641064

matlab_proxy/app_state.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -875,15 +875,8 @@ def create_logs_dir_for_MATLAB(self):
875875
user_code_output_file
876876
)
877877
logger.info(
878-
util.prettify(
879-
boundary_filler="*",
880-
text_arr=[
881-
f"When MATLAB starts, you can see the output for your startup code at:",
882-
f"{self.matlab_session_files.get('startup_code_output_file', ' ')}",
883-
],
884-
)
878+
f"The results of executing MWI_MATLAB_STARTUP_SCRIPT are stored at: {user_code_output_file} "
885879
)
886-
887880
return
888881

889882
def create_server_info_file(self):
@@ -909,17 +902,17 @@ def create_server_info_file(self):
909902

910903
# By default mwi_server_url usually points to 0.0.0.0 as the hostname, but this does not work well
911904
# on some browsers. Specifically on Safari (MacOS)
912-
logger.info(
913-
util.prettify(
914-
boundary_filler="=",
915-
text_arr=[
916-
f"Access MATLAB at:",
917-
self.settings["mwi_server_url"].replace("0.0.0.0", "localhost")
918-
+ mwi_auth_token_str,
919-
],
920-
)
905+
server_url = (
906+
self.settings["mwi_server_url"].replace("0.0.0.0", "localhost")
907+
+ mwi_auth_token_str
921908
)
922909

910+
mwi.logger.log_startup_info(
911+
title=f"matlab-proxy-app running on {self.settings['app_port']}",
912+
matlab_url=server_url,
913+
)
914+
logger.info(f"MATLAB Root: {self.settings['matlab_path']}")
915+
923916
def clean_up_mwi_server_session(self):
924917
# Clean up mwi_server_session_files
925918
try:
@@ -1004,7 +997,7 @@ async def __setup_env_for_matlab(self) -> dict:
1004997

1005998
# Set MW_CONNECTOR_CONTEXT_ROOT
1006999
matlab_env["MW_CONNECTOR_CONTEXT_ROOT"] = self.settings.get("base_url", "/")
1007-
logger.info(
1000+
logger.debug(
10081001
f"MW_CONNECTOR_CONTEXT_ROOT is set to: {matlab_env['MW_CONNECTOR_CONTEXT_ROOT']}"
10091002
)
10101003

@@ -1316,6 +1309,8 @@ async def start_matlab(self, restart_matlab=False):
13161309
# to MATLAB state by other functions/tasks until the lock is released, ensuring consistency. It's released early only in case of exceptions.
13171310
await self.matlab_state_updater_lock.acquire()
13181311
self.set_matlab_state("starting")
1312+
logger.info(f"Starting MATLAB...")
1313+
13191314
# Clear MATLAB errors and logging
13201315
self.error = None
13211316
self.logs["matlab"].clear()
@@ -1535,7 +1530,7 @@ async def stop_matlab(self, force_quit=False):
15351530
except:
15361531
pass
15371532

1538-
logger.info("Stopped (any running) MATLAB process.")
1533+
logger.debug("Stopped (any running) MATLAB process.")
15391534

15401535
# Terminating Xvfb
15411536
if system.is_posix():

matlab_proxy/settings.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def get_process_startup_timeout():
5353
)
5454
return constants.DEFAULT_PROCESS_START_TIMEOUT
5555

56-
logger.info(
56+
logger.debug(
5757
f"Using {constants.DEFAULT_PROCESS_START_TIMEOUT} seconds as the default timeout value"
5858
)
5959

@@ -94,7 +94,7 @@ def get_matlab_executable_and_root_path():
9494

9595
if matlab_executable_path:
9696
matlab_root_path = Path(matlab_executable_path).resolve().parent.parent
97-
logger.info(f"Found MATLAB executable at: {matlab_executable_path}")
97+
logger.debug(f"MATLAB root folder: {matlab_root_path}")
9898
matlab_root_path = mwi.validators.validate_matlab_root_path(
9999
matlab_root_path, is_custom_matlab_root=False
100100
)
@@ -698,7 +698,6 @@ def _get_matlab_cmd(matlab_executable_path, code_to_execute, nlm_conn_str):
698698
"-nosplash",
699699
*flag_to_hide_desktop,
700700
"-softwareopengl",
701-
# " v=mvm ",
702701
*matlab_lic_mode,
703702
"-externalUI",
704703
profile_matlab_startup,

matlab_proxy/util/__init__.py

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
interrupt_signal_caught = False
2727

2828

29-
def parse_cli_args():
29+
def parse_main_cli_args():
3030
"""Parses CLI arguments passed to the main() function.
3131
3232
Returns:
@@ -56,6 +56,28 @@ def parse_cli_args():
5656
return parsed_args
5757

5858

59+
def parse_list_cli_args():
60+
"""Parses CLI arguments passed to the matlab-proxy-app-list-servers entrypoint.
61+
62+
Returns:
63+
dict: Containing the parsed arguments
64+
"""
65+
# Parse the --config flag provided to the console script executable.
66+
parsed_args = {}
67+
parser = argparse.ArgumentParser()
68+
parser.add_argument(
69+
"-q",
70+
"--quiet",
71+
help="Return the server list without any additional text.",
72+
action="store_true",
73+
)
74+
args = parser.parse_args()
75+
76+
parsed_args["quiet"] = args.quiet
77+
78+
return parsed_args
79+
80+
5981
def prepare_site(app, runner):
6082
"""Prepares to launch a TCPSite. If MWI_APP_PORT env variable is set,
6183
it will setup a site to launch on that port, else will launch on a random available port.
@@ -148,47 +170,6 @@ def catch_interrupt_signal(*args):
148170
return loop
149171

150172

151-
def prettify(boundary_filler=" ", text_arr=[]):
152-
"""Prettify array of strings with borders for stdout
153-
154-
Args:
155-
boundary_filler (str, optional): Upper and lower border filler for text. Defaults to " ".
156-
text_arr (list, optional):The text array to prettify. Each element will be added to a newline. Defaults to [].
157-
158-
Returns:
159-
[str]: Prettified String
160-
"""
161-
162-
import sys
163-
164-
if not sys.stdout.isatty():
165-
return (
166-
"\n============================\n"
167-
+ "\n".join(text_arr)
168-
+ "\n============================\n"
169-
)
170-
171-
size = os.get_terminal_size()
172-
cols, _ = size.columns, size.lines
173-
174-
if any(len(text) > cols for text in text_arr):
175-
result = ""
176-
for text in text_arr:
177-
result += text + "\n"
178-
return result
179-
180-
upper = "\n" + "".ljust(cols, boundary_filler) + "\n" if len(text_arr) > 0 else ""
181-
lower = "".ljust(cols, boundary_filler) if len(text_arr) > 0 else ""
182-
183-
content = ""
184-
for text in text_arr:
185-
content += text.center(cols) + "\n"
186-
187-
result = upper + content + lower
188-
189-
return result
190-
191-
192173
def get_child_processes(parent_process, max_attempts=10, sleep_interval=1):
193174
"""Get list of child processes from a parent process.
194175

matlab_proxy/util/list_servers.py

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020-2022 The MathWorks, Inc.
1+
# Copyright (c) 2020-2025 The MathWorks, Inc.
22
# Script to print information about all running matlab-proxy servers for current user on current machine.
33

44
import glob
@@ -7,6 +7,66 @@
77
import matlab_proxy.settings as mwi_settings
88
import matlab_proxy.util as mwi_util
99

10+
from datetime import datetime
11+
from rich.console import Console
12+
from rich.table import Table
13+
14+
__NO_SERVERS_MSG = "No MATLAB-PROXY Servers are currently running."
15+
16+
17+
def _extract_version_and_session(title):
18+
"""Extracts session name and MATLAB version from the title."""
19+
parts = title.split("-")
20+
if len(parts) < 2:
21+
return title.replace("MATLAB ", ""), ""
22+
session_name = parts[0].strip()
23+
matlab_version = parts[1].strip().replace("MATLAB ", "")
24+
return matlab_version, session_name
25+
26+
27+
def _get_server_info(server):
28+
"""Helper function to parse info from server file."""
29+
with open(server) as f:
30+
# Assumes that the server file contains the address on the first line,
31+
# the browser_title on the second line, and the timestamp is derived from the file's last modified time.
32+
address = f.readline().strip()
33+
browser_title = f.readline().strip()
34+
matlab_version, session_name = _extract_version_and_session(browser_title)
35+
timestamp = _get_timestamp(server)
36+
return timestamp, matlab_version, session_name, address
37+
38+
39+
def _print_server_info_as_table(servers):
40+
console = Console()
41+
table = Table(
42+
title="MATLAB Proxy Servers",
43+
title_style="cyan",
44+
title_justify="center",
45+
caption="No servers found." if not servers else "",
46+
caption_style="bold red",
47+
show_header=True,
48+
header_style="yellow",
49+
show_lines=True,
50+
show_edge=True,
51+
)
52+
table.add_column("Created On")
53+
table.add_column("MATLAB\nVersion")
54+
table.add_column("Session Name")
55+
table.add_column("Server URL", overflow="fold")
56+
57+
# Build server information
58+
for server in servers:
59+
table.add_row(*_get_server_info(server))
60+
61+
console.print(table)
62+
63+
64+
def _get_timestamp(filename):
65+
"""Get the last modified timestamp of the file in a human-readable format."""
66+
timestamp = os.path.getmtime(filename)
67+
readable_time = datetime.fromtimestamp(timestamp).strftime("%d/%m/%y %H:%M:%S")
68+
return readable_time
69+
1070

1171
def print_server_info():
1272
"""Print information about all matlab-proxy servers (with version > 0.4.0) running on this machine"""
@@ -15,30 +75,15 @@ def print_server_info():
1575
# Look for files in port folders
1676
ports_folder = home_folder / "ports"
1777
search_string = str(ports_folder) + "/**/mwi_server.info"
78+
servers = sorted(glob.glob(search_string), key=os.path.getmtime)
1879

19-
print_output = str(
20-
mwi_util.prettify(
21-
boundary_filler="-",
22-
text_arr=["Your running servers are:"],
23-
)
24-
)
25-
print_output += "\n"
26-
search_results = sorted(glob.glob(search_string), key=os.path.getmtime)
27-
if len(search_results) == 0:
28-
print_output += "No MATLAB-PROXY Servers are currently running."
29-
else:
30-
server_number = 0
31-
for server in search_results:
32-
server_number += 1
80+
args = mwi_util.parse_list_cli_args()
81+
82+
if args["quiet"]:
83+
for server in servers:
3384
with open(server) as f:
3485
server_info = f.readline().strip()
35-
print_output += str(server_number) + ". " + str(server_info) + "\n"
36-
37-
print_output += str(
38-
mwi_util.prettify(
39-
boundary_filler="-",
40-
text_arr=["Thank you."],
41-
)
42-
)
43-
44-
return print_output
86+
print(f"{server_info}", end="\n")
87+
else:
88+
_print_server_info_as_table(servers)
89+
return

matlab_proxy/util/mwi/environment_variables.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,13 @@ def get_env_name_use_cookie_cache():
213213
def should_use_cookie_cache():
214214
"""Returns true if the cookie jar support is enabled."""
215215
return _is_env_set_to_true(Experimental.get_env_name_use_cookie_cache())
216+
217+
@staticmethod
218+
def get_env_name_use_rich_logging():
219+
"""Set to True to enable rich logging to console."""
220+
return "MWI_USE_RICH_LOGGING"
221+
222+
@staticmethod
223+
def use_rich_logger():
224+
"""Returns true if the cookie jar support is enabled."""
225+
return _is_env_set_to_true(Experimental.get_env_name_use_rich_logging())

0 commit comments

Comments
 (0)