Skip to content

Commit d44f19b

Browse files
committed
added function to log file content
1 parent fb7a78d commit d44f19b

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

services/dask-sidecar/src/simcore_service_dask_sidecar/computational_sidecar/core.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from pathlib import Path
88
from pprint import pformat
99
from types import TracebackType
10-
from typing import Final, cast
10+
from typing import cast
1111
from uuid import uuid4
1212

1313
from aiodocker import Docker
@@ -32,6 +32,7 @@
3232
from ..utils.dask import TaskPublisher
3333
from ..utils.files import (
3434
check_need_unzipping,
35+
log_partial_file_content,
3536
pull_file_from_remote,
3637
push_file_to_remote,
3738
)
@@ -49,7 +50,7 @@
4950

5051
_logger = logging.getLogger(__name__)
5152
CONTAINER_WAIT_TIME_SECS = 2
52-
_TASK_PROCESSING_PROGRESS_WEIGHT: Final[float] = 0.99
53+
MAX_LOGGED_FILE_CHARS = 40
5354

5455

5556
@dataclass(kw_only=True, frozen=True, slots=True)
@@ -147,11 +148,14 @@ async def _retrieve_output_data(
147148
upload_tasks = []
148149
for output_params in output_data.values():
149150
if isinstance(output_params, FileUrl):
150-
assert ( # nosec
151+
assert (
151152
output_params.file_mapping
152153
), f"{output_params.model_dump_json(indent=1)} expected resolved in TaskOutputData.from_task_output"
153154

154155
src_path = task_volumes.outputs_folder / output_params.file_mapping
156+
await log_partial_file_content(
157+
src_path, _logger, MAX_LOGGED_FILE_CHARS
158+
)
155159
upload_tasks.append(
156160
push_file_to_remote(
157161
src_path,

services/dask-sidecar/src/simcore_service_dask_sidecar/utils/files.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,17 @@ async def push_file_to_remote(
330330
f"Upload of '{src_path.name}' to '{dst_url.path.strip('/')}' complete",
331331
logging.INFO,
332332
)
333+
334+
335+
async def log_partial_file_content(
336+
src_path: Path, logger: logging.Logger, log_level: int, max_chars: int
337+
) -> None:
338+
if not src_path.exists():
339+
logger.log(log_level, "file does not exist: %s", src_path)
340+
return
341+
async with aiofiles.open(src_path, encoding="utf-8") as f:
342+
content = await f.read(max_chars + 1)
343+
if len(content) > max_chars:
344+
logger.log(log_level, "file content (truncated): %s...", content[:max_chars])
345+
else:
346+
logger.log(log_level, "file content: %s", content)

services/dask-sidecar/tests/unit/test_utils_files.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import asyncio
66
import hashlib
7+
import logging
78
import mimetypes
89
import zipfile
910
from collections.abc import AsyncIterable
@@ -21,6 +22,7 @@
2122
from settings_library.s3 import S3Settings
2223
from simcore_service_dask_sidecar.utils.files import (
2324
_s3fs_settings_from_s3_settings,
25+
log_partial_file_content,
2426
pull_file_from_remote,
2527
push_file_to_remote,
2628
)
@@ -511,3 +513,44 @@ async def test_push_file_to_remote_creates_reproducible_zip_archive(
511513
assert dst_path2.exists()
512514

513515
assert _compute_hash(dst_path1) == _compute_hash(dst_path2)
516+
517+
518+
async def test_log_partial_file_content(
519+
tmp_path: Path, caplog: pytest.LogCaptureFixture
520+
):
521+
# Create a file with known content
522+
file_content = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
523+
file_path = tmp_path / "testfile.txt"
524+
file_path.write_text(file_content)
525+
logger = logging.getLogger("pytest.utils.files")
526+
527+
# Case 1: file longer than max_chars
528+
with caplog.at_level(logging.DEBUG, logger=logger.name):
529+
await log_partial_file_content(file_path, logger, logging.DEBUG, max_chars=10)
530+
assert any(
531+
"file content (truncated): abcdefghij..." in record.getMessage()
532+
for record in caplog.records
533+
)
534+
535+
# Case 2: file shorter than max_chars
536+
caplog.clear()
537+
short_content = "short"
538+
short_file = tmp_path / "short.txt"
539+
short_file.write_text(short_content)
540+
with caplog.at_level(logging.DEBUG, logger=logger.name):
541+
await log_partial_file_content(short_file, logger, logging.DEBUG, max_chars=10)
542+
assert any(
543+
"file content: short" in record.getMessage() for record in caplog.records
544+
)
545+
546+
# Case 3: file does not exist
547+
caplog.clear()
548+
non_existent = tmp_path / "doesnotexist.txt"
549+
with caplog.at_level(logging.DEBUG, logger=logger.name):
550+
await log_partial_file_content(
551+
non_existent, logger, logging.DEBUG, max_chars=10
552+
)
553+
assert any(
554+
f"file does not exist: {non_existent}" in record.getMessage()
555+
for record in caplog.records
556+
)

0 commit comments

Comments
 (0)