Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ログを構造化ログに変更 #17

Merged
merged 4 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/infrastructure/s3_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@
import boto3
from mypy_boto3_s3 import S3Client
from domain.object_storage_repository_interface import ObjectStorageRepositoryInterface
from log.logging import AppLogger


def create_s3_client() -> S3Client:
return boto3.client("s3")


def create_s3_repository(s3_client: S3Client) -> ObjectStorageRepositoryInterface:
return S3Repository(s3_client)
def create_s3_repository(
s3_client: S3Client, logger: AppLogger
) -> ObjectStorageRepositoryInterface:
return S3Repository(s3_client, logger)


class S3Repository(ObjectStorageRepositoryInterface):
def __init__(self, s3_client: S3Client) -> None:
def __init__(self, s3_client: S3Client, logger: AppLogger) -> None:
self.s3_client = s3_client
self.logger = logger

def fetch_image(self, bucket_name: str, object_key: str) -> bytes:
self.logger.info("画像の取得を開始")

response = self.s3_client.get_object(Bucket=bucket_name, Key=object_key)
content = response["Body"].read()
return content
Expand All @@ -27,6 +33,8 @@ def upload_image(
object_key: str,
processed_image: io.BytesIO,
) -> None:
self.logger.info("画像のアップロードを開始")

self.s3_client.put_object(
Bucket=bucket_name, Key=object_key, Body=processed_image
)
Empty file added src/log/__init__.py
Empty file.
65 changes: 65 additions & 0 deletions src/log/logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import logging
import json
from typing import Any


class JSONFormatter(logging.Formatter):
def __init__(
self, request_id: str, process_type: str, bucket_name: str, object_key: str
) -> None:
super().__init__()
self.request_id = request_id
self.process_type = process_type
self.bucket_name = bucket_name
self.object_key = object_key

def format(self, record: logging.LogRecord) -> str:
log_data = {
"requestId": self.request_id,
"processType": self.process_type,
"bucketName": self.bucket_name,
"objectKey": self.object_key,
"filename": record.filename,
"funcName": record.funcName,
"levelname": record.levelname,
"lineno": record.lineno,
"module": record.module,
"message": record.getMessage(),
"pathname": record.pathname,
"timestamp": self.formatTime(record, self.datefmt),
"level": record.levelname,
}

if record.exc_info:
log_data["exception"] = self.formatException(record.exc_info)

def json_default(obj: Any) -> str:
return str(obj)

return json.dumps(log_data, default=json_default)


class AppLogger(logging.Logger):
def __init__(
self,
name: str,
request_id: str,
process_type: str,
bucket_name: str,
object_key: str,
) -> None:
super().__init__(name)
self.setLevel(logging.INFO)

handler = logging.StreamHandler()
formatter = JSONFormatter(request_id, process_type, bucket_name, object_key)
handler.setFormatter(formatter)

self.addHandler(handler)


def setup_logger(
request_id: str, process_type: str, bucket_name: str, object_key: str
) -> AppLogger:
logger = AppLogger(__name__, request_id, process_type, bucket_name, object_key)
return logger
4 changes: 3 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def lambda_handler(event: Event, context: Context) -> Response:
"Invalid input: process, bucketName, objectKey が設定されていません。"
)

handle_process(process, bucket_name, object_key)
request_id = context.aws_request_id # type: ignore

handle_process(request_id, process, bucket_name, object_key)

return format_response(bucket_name, object_key)
12 changes: 9 additions & 3 deletions src/presentation/handle_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys

from domain.object_storage_repository_interface import ObjectStorageRepositoryInterface
from log.logging import AppLogger, setup_logger
from infrastructure.s3_repository import (
create_s3_client,
create_s3_repository,
Expand All @@ -19,13 +20,18 @@ class ProcessType(Enum):
STORE_TO_DB = "storeToDb"


def handle_process(process: str, bucket_name: str, object_key: str) -> None:
def handle_process(
request_id: str, process: str, bucket_name: str, object_key: str
) -> None:
logger: AppLogger = setup_logger(request_id, process, bucket_name, object_key)
s3_client = create_s3_client()
s3_repository: ObjectStorageRepositoryInterface = create_s3_repository(s3_client)
s3_repository: ObjectStorageRepositoryInterface = create_s3_repository(
s3_client, logger
)

judge_image_usecase = JudgeImageUsecase(bucket_name, object_key)
generate_lgtm_image_usecase = GenerateLgtmImageUsecase(
s3_repository, bucket_name, object_key
s3_repository, bucket_name, object_key, logger
)
convert_to_webp_usecase = ConvertToWebpUsecase(bucket_name, object_key)
store_to_db_usecase = StoreToDbUsecase(bucket_name, object_key)
Expand Down
20 changes: 17 additions & 3 deletions src/usecase/generate_lgtmI_image_usecase.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
import os
from PIL import Image, ImageDraw, ImageFont
from domain.object_storage_repository_interface import ObjectStorageRepositoryInterface
from log.logging import AppLogger


def build_upload_object_key(object_key: str) -> str:
directory, filename = os.path.split(object_key)
imagename_without_ext = os.path.splitext(filename)[0]
return os.path.join(directory, imagename_without_ext + ".png")


class GenerateLgtmImageUsecase:
Expand All @@ -10,13 +17,15 @@ def __init__(
s3repository: ObjectStorageRepositoryInterface,
bucket_name: str,
object_key: str,
logger: AppLogger,
) -> None:
self.bucket_name = bucket_name
self.object_key = object_key
self.font_path = os.path.join(
os.environ["LAMBDA_TASK_ROOT"], "fonts", "MPLUSRounded1c-Medium.ttf"
)
self.s3repository = s3repository
self.logger = logger

def gemerate_lgtm_image(self, image_data: bytes) -> io.BytesIO:
with Image.open(io.BytesIO(image_data)) as img:
Expand Down Expand Up @@ -69,6 +78,7 @@ def gemerate_lgtm_image(self, image_data: bytes) -> io.BytesIO:
return buffer

def execute(self) -> None:
self.logger.info("LGTM画像の作成を開始")
try:
cat_image = self.s3repository.fetch_image(self.bucket_name, self.object_key)

Expand All @@ -80,14 +90,18 @@ def execute(self) -> None:
"環境変数 GENERATE_LGTM_IMAGE_UPLOAD_BUCKET が設定されていません"
)

upload_object_key = build_upload_object_key(self.object_key)

self.s3repository.upload_image(
upload_bucket_name, self.object_key, processed_image
upload_bucket_name, upload_object_key, processed_image
)

self.logger.info("LGTM画像の作成に成功")

except ValueError as e:
print(f"error: {e}")
self.logger.error(e, exc_info=True)
raise

except Exception as e:
print(f"Unexpected error: {e}")
self.logger.error(e, exc_info=True)
raise