@@ -147,6 +147,7 @@ class ChromeDaemon(object):
147
147
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ,
148
148
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" ,
149
149
]
150
+ SYSTEM_ENCODING = os .getenv ("SYSTEM_ENCODING" ) or ""
150
151
151
152
def __init__ (
152
153
self ,
@@ -482,30 +483,57 @@ def get_cmd_args(self):
482
483
)
483
484
if need_reopen :
484
485
_path = self .user_data_dir / stdout_path
485
- self .opened_files [0 ] = _path .open ("wb" )
486
+ self .opened_files [0 ] = _path .open ("wb+ " )
486
487
kwargs ["stdout" ] = self .opened_files [0 ]
487
488
logger .debug (f"stdout_path -> { _path .absolute ().as_posix ()} " )
488
489
if "stderr" not in kwargs and stderr_path :
489
490
if stderr_path == "/dev/null" :
490
491
kwargs ["stderr" ] = subprocess .DEVNULL
491
492
elif stdout_path and stderr_path == stdout_path :
492
493
kwargs ["stderr" ] = subprocess .STDOUT
494
+ self .opened_files [1 ] = self .opened_files [0 ]
493
495
else :
494
496
need_reopen = (
495
497
not self .opened_files [1 ] or self .opened_files [1 ].closed
496
498
)
497
499
if need_reopen :
498
500
_path = self .user_data_dir / stderr_path
499
- self .opened_files [1 ] = _path .open ("wb" )
501
+ self .opened_files [1 ] = _path .open ("wb+ " )
500
502
kwargs ["stderr" ] = self .opened_files [1 ]
501
503
logger .debug (f"stderr_path -> { _path .absolute ().as_posix ()} " )
502
504
self .cmd_args = kwargs
503
505
return kwargs
504
506
505
- def close_stdout_stderr (self ):
507
+ def close_stdout_stderr (self , error_name = "" ):
506
508
for f in self .opened_files :
507
509
try :
508
510
if f and not f .closed :
511
+ try :
512
+ if error_name and f is self .opened_files [1 ]:
513
+ last_5_lines = []
514
+ f .seek (0 )
515
+ for line in f :
516
+ if not line .strip ():
517
+ continue
518
+ last_5_lines .append (line )
519
+ if len (last_5_lines ) > 5 :
520
+ last_5_lines .pop (0 )
521
+ if last_5_lines :
522
+ content = b"" .join (last_5_lines )
523
+ if self .SYSTEM_ENCODING :
524
+ text = content .decode (self .SYSTEM_ENCODING )
525
+ else :
526
+ try :
527
+ text = content .decode ("utf-8" )
528
+ except UnicodeDecodeError :
529
+ text = content .decode (
530
+ "gb18030" , errors = "replace"
531
+ )
532
+ logger .error (
533
+ f"stderr file last 5 lines for { error_name } : { text } "
534
+ )
535
+ except Exception :
536
+ pass
509
537
f .close ()
510
538
except Exception :
511
539
pass
@@ -692,20 +720,23 @@ def restart(self):
692
720
def update_shutdown_time (self ):
693
721
self ._shutdown = time .time ()
694
722
695
- def shutdown (self , reason = None ):
723
+ def shutdown (self , reason = None , exc_type = None ):
696
724
if self ._shutdown :
697
725
logger .debug (f"{ self } shutdown at { ttime (self ._shutdown )} yet." )
698
726
return
699
727
self ._shutdown_reason = reason
700
728
self .update_shutdown_time ()
701
- reason = f" for { reason } " if reason else ""
702
- logger .debug (
703
- f"{ self } shutting down{ reason } , start-up: { ttime (self .start_time )} , duration: { read_time (time .time () - self .start_time )} ."
704
- )
729
+ msg = f"{ self } shutting down, reason={ reason !r} , start-up: { ttime (self .start_time )} , duration: { read_time (time .time () - self .start_time )} ."
730
+ if exc_type :
731
+ logger .exception (msg )
732
+ else :
733
+ logger .debug (msg )
705
734
if self .on_shutdown :
706
735
self .on_shutdown (self )
707
736
self .kill (True )
708
- self .close_stdout_stderr ()
737
+ self .close_stdout_stderr (
738
+ error_name = getattr (exc_type , "__name__" , repr (exc_type ))
739
+ )
709
740
if self .after_shutdown :
710
741
self .after_shutdown (self )
711
742
if self .clear_after_shutdown :
@@ -714,8 +745,8 @@ def shutdown(self, reason=None):
714
745
def __enter__ (self ):
715
746
return self
716
747
717
- def __exit__ (self , * args ):
718
- self .shutdown ("__exit__" )
748
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
749
+ self .shutdown ("__exit__" , exc_type )
719
750
720
751
@staticmethod
721
752
def get_proc (port , host = None ):
@@ -1013,8 +1044,8 @@ async def _daemon(self, interval=None):
1013
1044
async def __aenter__ (self ):
1014
1045
return await self ._init_coro
1015
1046
1016
- async def __aexit__ (self , * args , ** kwargs ):
1017
- await self .shutdown ("__aexit__" )
1047
+ async def __aexit__ (self , exc_type , exc_val , exc_tb ):
1048
+ await self .shutdown ("__aexit__" , exc_type = exc_type )
1018
1049
1019
1050
@property
1020
1051
def x (self ):
@@ -1024,21 +1055,25 @@ def x(self):
1024
1055
else :
1025
1056
return asyncio .sleep (0 )
1026
1057
1027
- async def shutdown (self , reason = None ):
1058
+ async def shutdown (self , reason = None , exc_type = None ):
1028
1059
"shutdown the chrome, but do not use it, use async with instead."
1029
1060
if self ._shutdown :
1030
1061
# logger.debug(f"{self} shutdown at {ttime(self._shutdown)} yet.")
1031
1062
return
1032
1063
self ._shutdown_reason = reason
1033
1064
self .update_shutdown_time ()
1034
- reason = f" for { reason } " if reason else ""
1035
- logger .debug (
1036
- f"{ self } shutting down{ reason } , start-up: { ttime (self .start_time )} , duration: { read_time (time .time () - self .start_time )} ."
1037
- )
1065
+ msg = f"{ self } shutting down, reason={ reason !r} , start-up: { ttime (self .start_time )} , duration: { read_time (time .time () - self .start_time )} ."
1066
+ if exc_type :
1067
+ logger .exception (msg )
1068
+ else :
1069
+ logger .debug (msg )
1038
1070
if self .on_shutdown :
1039
1071
await ensure_awaitable (self .on_shutdown (self ))
1040
1072
await async_run (self .kill , True )
1041
- await async_run (self .close_stdout_stderr )
1073
+ await async_run (
1074
+ self .close_stdout_stderr ,
1075
+ error_name = getattr (exc_type , "__name__" , repr (exc_type )),
1076
+ )
1042
1077
if self .after_shutdown :
1043
1078
await ensure_awaitable (self .after_shutdown (self ))
1044
1079
if self .clear_after_shutdown :
@@ -1145,7 +1180,7 @@ def __init__(self, start_port=9222, workers=1, kwargs=None):
1145
1180
self .start_port = start_port or 9222
1146
1181
self .workers = workers or 1
1147
1182
self .kwargs = kwargs or {}
1148
- self .daemons = []
1183
+ self .daemons : List [ AsyncChromeDaemon ] = []
1149
1184
self .tasks = []
1150
1185
1151
1186
async def __aenter__ (self ):
@@ -1170,9 +1205,9 @@ async def wait(self):
1170
1205
except asyncio .CancelledError :
1171
1206
pass
1172
1207
1173
- async def __aexit__ (self , * args ):
1208
+ async def __aexit__ (self , exc_type , exc_val , exc_tb ):
1174
1209
for daemon in self .daemons :
1175
- await daemon .shutdown ("__aexit__" )
1210
+ await daemon .shutdown ("__aexit__" , exc_type = exc_type )
1176
1211
1177
1212
@classmethod
1178
1213
async def run_chrome_workers (cls , start_port , workers , kwargs ):
0 commit comments