Skip to content

Commit b983ab1

Browse files
committed
add stdout_stderr to ChromeDaemon, to redirect subprocess stdout/stderr in user-data-dir
1 parent 1b22057 commit b983ab1

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

ichrome/daemon.py

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from inspect import isawaitable
1313
from json import loads as _json_loads
1414
from pathlib import Path
15-
from typing import List, Set, Union
15+
from typing import List, Literal, Optional, Set, Tuple, Union
1616

1717
from aiohttp import ClientSession
1818
from morebuiltins.request import req
@@ -171,7 +171,11 @@ def __init__(
171171
before_startup=None,
172172
after_shutdown=None,
173173
clear_after_shutdown=False,
174-
popen_kwargs: dict = None,
174+
popen_kwargs: Optional[dict] = None,
175+
stdout_stderr: Tuple[
176+
Literal["", "/dev/null", "stdout.log"],
177+
Literal["", "/dev/null", "stderr.log", "stdout.log"],
178+
] = ("stdout.log", "stdout.log"),
175179
):
176180
if debug:
177181
logger.setLevel("DEBUG")
@@ -192,7 +196,7 @@ def __init__(
192196
self.headless = headless
193197
self.proxy = proxy
194198
self.disable_image = disable_image
195-
self.user_data_dir = user_data_dir
199+
self.user_data_dir: Optional[Path] = user_data_dir
196200
self.start_url = start_url
197201
self.extra_config = extra_config
198202
self.proc_check_interval = proc_check_interval
@@ -206,6 +210,8 @@ def __init__(
206210
self.DEFAULT_POPEN_ARGS if popen_kwargs is None else popen_kwargs
207211
)
208212
self._use_port_dir = False
213+
self.stdout_stderr = stdout_stderr
214+
self.opened_files = [None, None]
209215
self.init()
210216

211217
@classmethod
@@ -453,18 +459,57 @@ def cmd(self):
453459
args.append(self.start_url)
454460
return args
455461

456-
def get_cmd_args(self):
462+
@property
463+
def cmd_string(self):
457464
# list2cmdline for linux use args list failed...
458-
cmd_string = subprocess.list2cmdline(self.cmd)
459-
logger.debug(f"running with: {cmd_string}")
460-
kwargs = {"args": cmd_string, "shell": True}
461-
if not self.debug:
462-
kwargs["stdout"] = subprocess.DEVNULL
463-
kwargs["stderr"] = subprocess.DEVNULL
465+
return subprocess.list2cmdline(self.cmd)
466+
467+
def get_cmd_args(self):
468+
kwargs = {"args": self.cmd_string, "shell": True}
469+
msg = f"running with: {kwargs['args']}."
470+
logger.debug(msg)
471+
# kwargs["stdout"] = subprocess.DEVNULL
472+
# kwargs["stderr"] = subprocess.DEVNULL
464473
kwargs.update(self.popen_kwargs)
474+
if self.user_data_dir and "text" not in kwargs:
475+
stdout_path, stderr_path = self.stdout_stderr
476+
if "stdout" not in kwargs and stdout_path:
477+
if stdout_path == "/dev/null":
478+
kwargs["stdout"] = subprocess.DEVNULL
479+
else:
480+
need_reopen = (
481+
not self.opened_files[0] or self.opened_files[0].closed
482+
)
483+
if need_reopen:
484+
_path = self.user_data_dir / stdout_path
485+
self.opened_files[0] = _path.open("wb")
486+
kwargs["stdout"] = self.opened_files[0]
487+
logger.debug(f"stdout_path -> {_path.absolute().as_posix()}")
488+
if "stderr" not in kwargs and stderr_path:
489+
if stderr_path == "/dev/null":
490+
kwargs["stderr"] = subprocess.DEVNULL
491+
elif stdout_path and stderr_path == stdout_path:
492+
kwargs["stderr"] = subprocess.STDOUT
493+
else:
494+
need_reopen = (
495+
not self.opened_files[1] or self.opened_files[1].closed
496+
)
497+
if need_reopen:
498+
_path = self.user_data_dir / stderr_path
499+
self.opened_files[1] = _path.open("wb")
500+
kwargs["stderr"] = self.opened_files[1]
501+
logger.debug(f"stderr_path -> {_path.absolute().as_posix()}")
465502
self.cmd_args = kwargs
466503
return kwargs
467504

505+
def close_stdout_stderr(self):
506+
for f in self.opened_files:
507+
try:
508+
if f and not f.closed:
509+
f.close()
510+
except Exception:
511+
pass
512+
468513
def _start_chrome_process(self):
469514
self.chrome_proc_start_time = time.time()
470515
self.proc = subprocess.Popen(**self.get_cmd_args())
@@ -660,6 +705,7 @@ def shutdown(self, reason=None):
660705
if self.on_shutdown:
661706
self.on_shutdown(self)
662707
self.kill(True)
708+
self.close_stdout_stderr()
663709
if self.after_shutdown:
664710
self.after_shutdown(self)
665711
if self.clear_after_shutdown:
@@ -755,7 +801,7 @@ async def main():
755801
asyncio.run(main())
756802
757803
'''
758-
__doc__ = ChromeDaemon.__doc__ + _demo
804+
__doc__ = (ChromeDaemon.__doc__ or "") + _demo
759805

760806
def __init__(
761807
self,
@@ -780,7 +826,11 @@ def __init__(
780826
before_startup=None,
781827
after_shutdown=None,
782828
clear_after_shutdown=False,
783-
popen_kwargs: dict = None,
829+
popen_kwargs: Optional[dict] = None,
830+
stdout_stderr: Tuple[
831+
Literal["", "/dev/null", "stdout.log"],
832+
Literal["", "/dev/null", "stderr.log", "stdout.log"],
833+
] = ("stdout.log", "stdout.log"),
784834
):
785835
super().__init__(
786836
chrome_path=chrome_path,
@@ -805,6 +855,7 @@ def __init__(
805855
after_shutdown=after_shutdown,
806856
clear_after_shutdown=clear_after_shutdown,
807857
popen_kwargs=popen_kwargs,
858+
stdout_stderr=stdout_stderr,
808859
)
809860

810861
def init(self):
@@ -987,6 +1038,7 @@ async def shutdown(self, reason=None):
9871038
if self.on_shutdown:
9881039
await ensure_awaitable(self.on_shutdown(self))
9891040
await async_run(self.kill, True)
1041+
await async_run(self.close_stdout_stderr)
9901042
if self.after_shutdown:
9911043
await ensure_awaitable(self.after_shutdown(self))
9921044
if self.clear_after_shutdown:

0 commit comments

Comments
 (0)