Skip to content

Commit 90417f1

Browse files
naderzareSK2iP
authored andcommitted
add logger file and improve loggers
1 parent fff81ea commit 90417f1

File tree

4 files changed

+141
-38
lines changed

4 files changed

+141
-38
lines changed

server.py

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,31 @@
44
import service_pb2 as pb2
55
from typing import Union
66
from multiprocessing import Manager, Lock
7+
from utils.logger_utils import setup_logger
78
import logging
89
import grpc
910
import argparse
1011

1112

12-
logging.basicConfig(level=logging.DEBUG)
13+
console_logging_level = logging.INFO
14+
file_logging_level = logging.DEBUG
15+
16+
main_logger = setup_logger("pmservice", "logs/pmservice.log", console_level=console_logging_level, file_level=file_logging_level)
17+
1318

1419
class GrpcAgent:
15-
def __init__(self, agent_type, uniform_number) -> None:
20+
def __init__(self, agent_type, uniform_number, logger) -> None:
1621
self.agent_type: pb2.AgentType = agent_type
1722
self.uniform_number: int = uniform_number
1823
self.server_params: Union[pb2.ServerParam, None] = None
1924
self.player_params: Union[pb2.PlayerParam, None] = None
2025
self.player_types: dict[int, pb2.PlayerType] = {}
2126
self.debug_mode: bool = False
27+
self.logger: logging.Logger = logger
2228

2329
def GetAction(self, state: pb2.State):
30+
self.logger.debug(f"================================= cycle={state.world_model.cycle}.{state.world_model.stoped_cycle} =================================")
31+
# self.logger.debug(f"State: {state}")
2432
if self.agent_type == pb2.AgentType.PlayerT:
2533
return self.GetPlayerActions(state)
2634
elif self.agent_type == pb2.AgentType.CoachT:
@@ -50,8 +58,19 @@ def GetPlayerActions(self, state: pb2.State):
5058
actions.append(pb2.PlayerAction(helios_basic_move=pb2.HeliosBasicMove()))
5159
else:
5260
actions.append(pb2.PlayerAction(helios_set_play=pb2.HeliosSetPlay()))
61+
62+
self.logger.debug(f"Actions: {actions}")
5363
return pb2.PlayerActions(actions=actions)
5464

65+
def GetBestPlannerAction(self, pairs: pb2.BestPlannerActionRequest):
66+
self.logger.debug(f"GetBestPlannerAction cycle:{pairs.state.world_model.cycle} pairs:{len(pairs.pairs)} unum:{pairs.state.register_response.uniform_number}")
67+
pairs_list: list[int, pb2.RpcActionState] = [(k, v) for k, v in pairs.pairs.items()]
68+
pairs_list.sort(key=lambda x: x[0])
69+
best_action = max(pairs_list, key=lambda x: -1000 if x[1].action.parent_index != -1 else x[1].predict_state.ball_position.x)
70+
self.logger.debug(f"Best action: {best_action[0]} {best_action[1].action.description} to {best_action[1].action.target_unum} in ({round(best_action[1].action.target_point.x, 2)},{round(best_action[1].action.target_point.y, 2)}) e:{round(best_action[1].evaluation,2)}")
71+
res = pb2.BestPlannerActionResponse(index=best_action[0])
72+
return res
73+
5574
def GetCoachActions(self, state: pb2.State):
5675
actions = []
5776
actions.append(pb2.CoachAction(do_helios_substitute=pb2.DoHeliosSubstitute()))
@@ -74,6 +93,21 @@ def GetTrainerActions(self, state: pb2.State):
7493
)
7594
)
7695
return pb2.TrainerActions(actions=actions)
96+
97+
def SetServerParams(self, server_params: pb2.ServerParam):
98+
self.logger.debug(f"Server params received unum {server_params.register_response.uniform_number}")
99+
# self.logger.debug(f"Server params: {server_params}")
100+
self.server_params = server_params
101+
102+
def SetPlayerParams(self, player_params: pb2.PlayerParam):
103+
self.logger.debug(f"Player params received unum {player_params.register_response.uniform_number}")
104+
# self.logger.debug(f"Player params: {player_params}")
105+
self.player_params = player_params
106+
107+
def SetPlayerType(self, player_type: pb2.PlayerType):
108+
self.logger.debug(f"Player type received unum {player_type.register_response.uniform_number}")
109+
# self.logger.debug(f"Player type: {player_type}")
110+
self.player_types[player_type.id] = player_type
77111

78112
class GameHandler(pb2_grpc.GameServicer):
79113
def __init__(self, shared_lock, shared_number_of_connections) -> None:
@@ -82,91 +116,89 @@ def __init__(self, shared_lock, shared_number_of_connections) -> None:
82116
self.shared_number_of_connections = shared_number_of_connections
83117

84118
def GetPlayerActions(self, state: pb2.State, context):
85-
logging.debug(f"GetPlayerActions unum {state.register_response.uniform_number} at {state.world_model.cycle}")
119+
main_logger.debug(f"GetPlayerActions unum {state.register_response.uniform_number} at {state.world_model.cycle}")
86120
res = self.agents[state.register_response.client_id].GetAction(state)
87-
logging.debug(f"GetPlayerActions Done unum {res}")
88121
return res
89122

90123
def GetCoachActions(self, state: pb2.State, context):
91-
logging.debug(f"GetCoachActions coach at {state.world_model.cycle}")
124+
main_logger.debug(f"GetCoachActions coach at {state.world_model.cycle}")
92125
res = self.agents[state.register_response.client_id].GetAction(state)
93126
return res
94127

95128
def GetTrainerActions(self, state: pb2.State, context):
96-
logging.debug(f"GetTrainerActions trainer at {state.world_model.cycle}")
129+
main_logger.debug(f"GetTrainerActions trainer at {state.world_model.cycle}")
97130
res = self.agents[state.register_response.client_id].GetAction(state)
98131
return res
99132

100133
def SendServerParams(self, serverParams: pb2.ServerParam, context):
101-
logging.debug(f"Server params received unum {serverParams.register_response.uniform_number}")
102-
self.agents[serverParams.register_response.client_id].server_params = serverParams
134+
main_logger.debug(f"Server params received unum {serverParams.register_response.uniform_number}")
135+
self.agents[serverParams.register_response.client_id].SetServerParams(serverParams)
103136
res = pb2.Empty()
104137
return res
105138

106139
def SendPlayerParams(self, playerParams: pb2.PlayerParam, context):
107-
logging.debug(f"Player params received unum {playerParams.register_response.uniform_number}")
108-
self.agents[playerParams.register_response.client_id].player_params = playerParams
140+
main_logger.debug(f"Player params received unum {playerParams.register_response.uniform_number}")
141+
self.agents[playerParams.register_response.client_id].SetPlayerParams(playerParams)
109142
res = pb2.Empty()
110143
return res
111144

112145
def SendPlayerType(self, playerType: pb2.PlayerType, context):
113-
logging.debug(f"Player type received unum {playerType.register_response.uniform_number}")
114-
self.agents[playerType.register_response.client_id].player_types[playerType.id] = playerType
146+
main_logger.debug(f"Player type received unum {playerType.register_response.uniform_number}")
147+
self.agents[playerType.register_response.client_id].SetPlayerType(playerType)
115148
res = pb2.Empty()
116149
return res
117150

118151
def SendInitMessage(self, initMessage: pb2.InitMessage, context):
119-
logging.debug(f"Init message received unum {initMessage.register_response.uniform_number}")
152+
main_logger.debug(f"Init message received unum {initMessage.register_response.uniform_number}")
120153
self.agents[initMessage.register_response.client_id].debug_mode = initMessage.debug_mode
121154
res = pb2.Empty()
122155
return res
123156

124157
def Register(self, register_request: pb2.RegisterRequest, context):
125-
logging.debug(f"received register request from team_name: {register_request.team_name} "
126-
f"unum: {register_request.uniform_number} "
127-
f"agent_type: {register_request.agent_type}")
128158
with self.shared_lock:
159+
main_logger.info(f"received register request from team_name: {register_request.team_name} "
160+
f"unum: {register_request.uniform_number} "
161+
f"agent_type: {register_request.agent_type}")
129162
self.shared_number_of_connections.value += 1
130-
logging.debug(f"Number of connections {self.shared_number_of_connections.value}")
163+
main_logger.info(f"Number of connections {self.shared_number_of_connections.value}")
131164
team_name = register_request.team_name
132165
uniform_number = register_request.uniform_number
133166
agent_type = register_request.agent_type
134-
self.agents[self.shared_number_of_connections.value] = GrpcAgent(agent_type, uniform_number)
135-
res = pb2.RegisterResponse(client_id=self.shared_number_of_connections.value,
167+
register_response = pb2.RegisterResponse(client_id=self.shared_number_of_connections.value,
136168
team_name=team_name,
137169
uniform_number=uniform_number,
138170
agent_type=agent_type)
139-
return res
171+
logger = setup_logger(f"agent{register_response.uniform_number}_{register_response.client_id}")
172+
self.agents[self.shared_number_of_connections.value] = GrpcAgent(agent_type, uniform_number, logger)
173+
return register_response
140174

141175
def SendByeCommand(self, register_response: pb2.RegisterResponse, context):
142-
logging.debug(f"Bye command received unum {register_response.uniform_number}")
176+
main_logger.debug(f"Bye command received unum {register_response.uniform_number}")
143177
# with shared_lock:
144178
self.agents.pop(register_response.client_id)
145179

146180
res = pb2.Empty()
147181
return res
148182

149183
def GetBestPlannerAction(self, pairs: pb2.BestPlannerActionRequest, context):
150-
logging.debug(f"GetBestPlannerAction cycle:{pairs.state.world_model.cycle} pairs:{len(pairs.pairs)} unum:{pairs.state.register_response.uniform_number}")
151-
pairs_list: list[int, pb2.RpcActionState] = [(k, v) for k, v in pairs.pairs.items()]
152-
pairs_list.sort(key=lambda x: x[0])
153-
best_action = max(pairs_list, key=lambda x: -1000 if x[1].action.parent_index != -1 else x[1].predict_state.ball_position.x)
154-
logging.debug(f"Best action: {best_action[0]} {best_action[1].action.description} to {best_action[1].action.target_unum} in ({round(best_action[1].action.target_point.x, 2)},{round(best_action[1].action.target_point.y, 2)}) e:{round(best_action[1].evaluation,2)}")
155-
res = pb2.BestPlannerActionResponse(index=best_action[0])
184+
main_logger.debug(f"GetBestPlannerAction cycle:{pairs.state.world_model.cycle} pairs:{len(pairs.pairs)} unum:{pairs.state.register_response.uniform_number}")
185+
res = self.agents[pairs.state.register_response.client_id].GetBestPlannerAction(pairs)
156186
return res
187+
157188

158189
def serve(port, shared_lock, shared_number_of_connections):
159190
server = grpc.server(futures.ThreadPoolExecutor(max_workers=22))
160191
game_service = GameHandler(shared_lock, shared_number_of_connections)
161192
pb2_grpc.add_GameServicer_to_server(game_service, server)
162193
server.add_insecure_port(f'[::]:{port}')
163194
server.start()
164-
logging.info(f"Starting server on port {port}")
195+
main_logger.info(f"Starting server on port {port}")
165196

166197
server.wait_for_termination()
167198

168199

169200
def main():
201+
main_logger.info("Starting server")
170202
manager = Manager()
171203
shared_lock = Lock() # Create a Lock for synchronization
172204
shared_number_of_connections = manager.Value('i', 0)

start-team.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
import logging
66
import argparse
77
import check_requirements
8+
from utils.logger_utils import setup_logger
89

910

11+
# remove logs directory
12+
os.system("rm -rf logs")
13+
1014
# Set up logging
11-
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
15+
start_team_logger = setup_logger('start-team', 'logs/start-team.log', console_level=logging.DEBUG, file_level=logging.DEBUG, console_format_str='%(message)s')
1216

1317
def run_server_script(args):
1418
# Start the server.py script as a new process group
@@ -31,12 +35,20 @@ def run_start_script(args):
3135
)
3236
return process
3337

34-
def stream_output(process, prefix):
38+
def stream_output_to_console(process, prefix):
3539
# Stream output from the process and log it with a prefix
3640
for line in iter(process.stdout.readline, b''):
37-
logging.debug(f'{prefix} {line.decode().strip()}')
41+
start_team_logger.debug(f'{prefix} {line.decode().strip()}')
3842
process.stdout.close()
3943

44+
def stream_output_to_file(process, prefix):
45+
# Stream output from the process and log it with a prefix
46+
logger = setup_logger(prefix, console_level=None, file_level=logging.DEBUG)
47+
for line in iter(process.stdout.readline, b''):
48+
logger.info(line.decode().strip())
49+
pass
50+
process.stdout.close()
51+
4052
def kill_process_group(process):
4153
try:
4254
os.killpg(os.getpgid(process.pid), signal.SIGTERM) # Send SIGTERM to the process group
@@ -52,20 +64,20 @@ def kill_process_group(process):
5264

5365
try:
5466
# Check Python requirements
55-
logging.debug("Checking Python requirements...")
67+
start_team_logger.debug("Checking Python requirements...")
5668
check_requirements.check_requirements()
5769

5870
# Run the server.py script first
5971
server_process = run_server_script(args)
60-
logging.debug(f"Started server.py process with PID: {server_process.pid}")
72+
start_team_logger.debug(f"Started server.py process with PID: {server_process.pid}")
6173

6274
# Run the start.sh script after server.py with the given arguments
6375
start_process = run_start_script(args)
64-
logging.debug(f"Started start.sh process with PID: {start_process.pid} with team name {args=}")
76+
start_team_logger.debug(f"Started start.sh process with PID: {start_process.pid} with team name {args=}")
6577

6678
# Monitor both processes and log their outputs
67-
server_thread = threading.Thread(target=stream_output, args=(server_process, 'server:'))
68-
start_thread = threading.Thread(target=stream_output, args=(start_process, 'team:'))
79+
server_thread = threading.Thread(target=stream_output_to_console, args=(server_process, 'server:'))
80+
start_thread = threading.Thread(target=stream_output_to_file, args=(start_process, 'proxy:'))
6981

7082
server_thread.start()
7183
start_thread.start()
@@ -75,7 +87,7 @@ def kill_process_group(process):
7587
start_thread.join()
7688

7789
except KeyboardInterrupt:
78-
logging.debug("Interrupted! Killing all processes.")
90+
start_team_logger.debug("Interrupted! Killing all processes.")
7991
kill_process_group(server_process)
8092
kill_process_group(start_process)
8193

start-team.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
#!/bin/bash
22

3+
# remove logs directory
4+
rm -rf logs
5+
# create logs directory
6+
if [ ! -d "./logs" ]; then
7+
mkdir -p "./logs"
8+
fi
9+
310
# Ensure the script exits if any command fails
411
set -e
512
# check scripts/proxy directory does not exist, raise error
@@ -67,8 +74,10 @@ sleep 2
6774

6875
# Start start.sh script in the correct directory with arguments
6976
echo "Starting start.sh with team name: $team_name and ..."
77+
log_dir="logs/proxy.log"
78+
abspath=$(realpath $log_dir)
7079
cd scripts/proxy
71-
bash start.sh -t "$team_name" --rpc-port $rpc_port --rpc-type grpc &
80+
bash start.sh -t "$team_name" --rpc-port $rpc_port --rpc-type grpc >> $abspath 2>&1 &
7281
start_pid=$!
7382

7483
# Wait for both background processes to finish

utils/logger_utils.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import logging
2+
import os
3+
4+
5+
def setup_logger(name, log_file=None, console_level=logging.INFO, file_level=logging.DEBUG, console_format_str=None, file_format_str=None):
6+
"""
7+
Set up a logger that writes to both a file and the console, with different formats and levels.
8+
9+
:param name: Name of the logger.
10+
:param log_file: Path to the log file.
11+
:param console_level: Logging level for the console output.
12+
:param file_level: Logging level for the file output.
13+
:return: Configured logger.
14+
"""
15+
have_console_handler = console_level is not None
16+
have_file_handler = file_level is not None
17+
if log_file is None:
18+
log_file = os.path.join('logs', f'{name}.log')
19+
# Directory
20+
directory = os.path.dirname(log_file)
21+
if directory and not os.path.exists(directory):
22+
os.makedirs(directory)
23+
24+
print(f"have_console_handler={have_console_handler}, have_file_handler={have_file_handler}", log_file, directory)
25+
# Create a custom logger
26+
logger = logging.getLogger(name)
27+
28+
if not logger.hasHandlers():
29+
logger.setLevel(logging.DEBUG) # Set the overall logger level to the lowest level you want to capture
30+
# Console handler
31+
if have_console_handler:
32+
console_handler = logging.StreamHandler() # For console output
33+
console_handler.setLevel(console_level)
34+
if not console_format_str:
35+
console_format_str = '%(name)s - %(levelname)s - %(message)s'
36+
console_format = logging.Formatter(console_format_str)
37+
console_handler.setFormatter(console_format)
38+
logger.addHandler(console_handler)
39+
40+
# File handler
41+
if have_file_handler:
42+
file_handler = logging.FileHandler(log_file) # For file output
43+
file_handler.setLevel(file_level)
44+
if not file_format_str:
45+
file_format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
46+
file_format = logging.Formatter(file_format_str)
47+
file_handler.setFormatter(file_format)
48+
logger.addHandler(file_handler)
49+
50+
return logger

0 commit comments

Comments
 (0)