mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-05-05 05:01:49 +02:00
Log container output in dev mode
Additionally save a file with the container output next to the original file `[original].pdf.container_log`. This is needed in order to increase visibility of non-critical errors/warnings. Previously some issues went undetected because if this [1]. [1]: https://github.com/freedomofpress/dangerzone/issues/316
This commit is contained in:
parent
541fe7f382
commit
134dc27364
2 changed files with 42 additions and 12 deletions
|
@ -29,7 +29,9 @@ TIMEOUT_PER_PAGE: float = 10 # (seconds)
|
||||||
TIMEOUT_PER_MB: float = 10 # (seconds)
|
TIMEOUT_PER_MB: float = 10 # (seconds)
|
||||||
|
|
||||||
|
|
||||||
async def read_stream(sr: asyncio.StreamReader, callback: Callable = None) -> bytes:
|
async def read_stream(
|
||||||
|
cmd_args: List[str], sr: asyncio.StreamReader, callback: Callable = None
|
||||||
|
) -> bytes:
|
||||||
"""Consume a byte stream line-by-line.
|
"""Consume a byte stream line-by-line.
|
||||||
|
|
||||||
Read all lines in a stream until EOF. If a user has passed a callback, call it for
|
Read all lines in a stream until EOF. If a user has passed a callback, call it for
|
||||||
|
@ -44,10 +46,10 @@ async def read_stream(sr: asyncio.StreamReader, callback: Callable = None) -> by
|
||||||
line = await sr.readline()
|
line = await sr.readline()
|
||||||
if sr.at_eof():
|
if sr.at_eof():
|
||||||
break
|
break
|
||||||
|
if os.environ.get("DZ_DEBUG_CONTAINER", "no") == "yes":
|
||||||
|
print(f"DEBUG:{cmd_args[0]}: {line.decode().rstrip()}")
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
callback(line)
|
callback(line)
|
||||||
# TODO: This would be a good place to log the received line, mostly for debug
|
|
||||||
# logging.
|
|
||||||
buf += line
|
buf += line
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
@ -82,8 +84,8 @@ async def run_command(
|
||||||
|
|
||||||
# Create asynchronous tasks that will consume the standard streams of the command,
|
# Create asynchronous tasks that will consume the standard streams of the command,
|
||||||
# and call callbacks if necessary.
|
# and call callbacks if necessary.
|
||||||
stdout_task = asyncio.create_task(read_stream(proc.stdout, stdout_callback))
|
stdout_task = asyncio.create_task(read_stream(args, proc.stdout, stdout_callback))
|
||||||
stderr_task = asyncio.create_task(read_stream(proc.stderr, stderr_callback))
|
stderr_task = asyncio.create_task(read_stream(args, proc.stderr, stderr_callback))
|
||||||
|
|
||||||
# Wait until the command has finished, for a specific timeout. Then, verify that the
|
# Wait until the command has finished, for a specific timeout. Then, verify that the
|
||||||
# command has completed successfully. In any other case, raise an exception.
|
# command has completed successfully. In any other case, raise an exception.
|
||||||
|
|
|
@ -7,6 +7,7 @@ import pipes
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Callable, List, Optional, Tuple
|
from typing import Callable, List, Optional, Tuple
|
||||||
|
|
||||||
|
@ -134,17 +135,39 @@ class Container(IsolationProvider):
|
||||||
|
|
||||||
return installed
|
return installed
|
||||||
|
|
||||||
def parse_progress(self, document: Document, line: str) -> Tuple[bool, str, int]:
|
def log_container_output(
|
||||||
|
self, document: Document, line: str, error: bool = False
|
||||||
|
) -> None:
|
||||||
|
if not getattr(sys, "dangerzone_dev", False):
|
||||||
|
# Skip logging when in production mode
|
||||||
|
return
|
||||||
|
if error:
|
||||||
|
line = f"error: {line}"
|
||||||
|
log.debug(f"[ CONTAINER ] {line.rstrip()}")
|
||||||
|
|
||||||
|
# Log to .log file
|
||||||
|
if os.environ.get("DZ_LOG_CONTAINER", "no").lower() in ["yes", "true"]:
|
||||||
|
with open(f"{document.input_filename}.container_log", "a") as f:
|
||||||
|
f.write(f"{line.rstrip()}\n")
|
||||||
|
|
||||||
|
def parse_progress(
|
||||||
|
self, document: Document, line: str
|
||||||
|
) -> None | Tuple[bool, str, int]:
|
||||||
"""
|
"""
|
||||||
Parses a line returned by the container.
|
Parses a line returned by the container.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
status = json.loads(line)
|
status = json.loads(line)
|
||||||
except:
|
except:
|
||||||
error_message = f"Invalid JSON returned from container:\n\n\t {line}"
|
if line.startswith("DEBUG:") and getattr(sys, "dangerzone_dev", False):
|
||||||
log.error(error_message)
|
self.log_container_output(document, line.lstrip("DEBUG:"))
|
||||||
return (True, error_message, -1)
|
return None
|
||||||
|
else:
|
||||||
|
error_message = f"Invalid JSON returned from container:\n\n\t {line}"
|
||||||
|
log.error(error_message)
|
||||||
|
return (True, error_message, -1)
|
||||||
|
|
||||||
|
self.log_container_output(document, status["text"], status["error"])
|
||||||
self.print_progress(
|
self.print_progress(
|
||||||
document, status["error"], status["text"], status["percentage"]
|
document, status["error"], status["text"], status["percentage"]
|
||||||
)
|
)
|
||||||
|
@ -170,9 +193,11 @@ class Container(IsolationProvider):
|
||||||
) as p:
|
) as p:
|
||||||
if p.stdout is not None:
|
if p.stdout is not None:
|
||||||
for line in p.stdout:
|
for line in p.stdout:
|
||||||
(error, text, percentage) = self.parse_progress(document, line)
|
progress_tuple = self.parse_progress(document, line)
|
||||||
if stdout_callback:
|
if progress_tuple is not None:
|
||||||
stdout_callback(error, text, percentage)
|
(error, text, percentage) = progress_tuple
|
||||||
|
if stdout_callback:
|
||||||
|
stdout_callback(error, text, percentage)
|
||||||
|
|
||||||
p.communicate()
|
p.communicate()
|
||||||
return p.returncode
|
return p.returncode
|
||||||
|
@ -274,6 +299,9 @@ class Container(IsolationProvider):
|
||||||
"-e",
|
"-e",
|
||||||
f"ENABLE_TIMEOUTS={self.enable_timeouts}",
|
f"ENABLE_TIMEOUTS={self.enable_timeouts}",
|
||||||
]
|
]
|
||||||
|
if getattr(sys, "dangerzone_dev", False):
|
||||||
|
extra_args += ["-e", f"DZ_DEBUG_CONTAINER=yes"]
|
||||||
|
|
||||||
ret = self.exec_container(document, command, extra_args, stdout_callback)
|
ret = self.exec_container(document, command, extra_args, stdout_callback)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
log.error("documents-to-pixels failed")
|
log.error("documents-to-pixels failed")
|
||||||
|
|
Loading…
Reference in a new issue