Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Enhance logging capabilities and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
thought-tobi committed Apr 18, 2024
1 parent 3e85a96 commit 7d9de86
Show file tree
Hide file tree
Showing 15 changed files with 82 additions and 23 deletions.
30 changes: 15 additions & 15 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "telegram-mood-tracker"
version = "0.4.0"
version = "0.4.4"
description = ""
authors = ["Tobias Waslowski <[email protected]>"]
readme = "README.md"
Expand Down
1 change: 1 addition & 0 deletions scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ sudo docker run -d --rm \
--log-driver=awslogs \
--log-opt awslogs-region="$LOG_REGION" \
--log-opt awslogs-group="$LOG_GROUP" \
--log-opt awslogs-multiline-pattern='^ERROR' \
--security-opt seccomp:unconfined \
-v "$HOME/.aws/credentials:/root/.aws/credentials:ro" \
-v ./config.yaml:/app/config.yaml \
Expand Down
2 changes: 1 addition & 1 deletion src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

TOKEN = os.environ.get("TELEGRAM_TOKEN")
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
format=" %(levelname)s - %(asctime)s - %(name)s - %(message)s", level=logging.INFO
)
logging.getLogger("httpx").setLevel(logging.WARNING)

Expand Down
5 changes: 4 additions & 1 deletion src/handlers/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from telegram.ext import CallbackContext


async def error_handler(update: Update, context: CallbackContext):
async def error_handler(update: Update, context: CallbackContext) -> None:
"""Log all errors."""
error_message = context.error
logging.error(msg="Exception while handling an update:", exc_info=error_message)
# This fails when the error is not directly caused by a user updated, e.g. in a JobQueue job
if update is None:
logging.error("Update is None, cannot send error message to user.")
return
await update.effective_user.send_message(
text=f"An error occurred while processing your message: {error_message}."
)
2 changes: 1 addition & 1 deletion src/handlers/record_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def store_record(
:param user_record: the temporary record being saved
:return:
"""
logging.info(f"Record for user {user_id} is complete: {user_record}")
logging.info(f"Persisting record for user {user_id}: {user_record}")
record_repository.create_record(
user_id,
user_record.data,
Expand Down
3 changes: 2 additions & 1 deletion src/handlers/util.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import logging

from telegram import Update
from telegram.error import TimedOut
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type


@retry(
stop=stop_after_attempt(3),
wait=wait_fixed(1),
retry=retry_if_exception_type(TimeoutError),
retry=retry_if_exception_type((TimeoutError, TimedOut)),
)
async def send(update: Update, text: str):
"""
Expand Down
6 changes: 6 additions & 0 deletions src/model/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ def serialize(self):
"timestamp": self.timestamp.isoformat(),
}

def __str__(self):
return f"user_id: {self.user_id}, data: {self.data}, timestamp: {self.timestamp.isoformat()}"


class TempRecord(BaseModel):
"""
Expand All @@ -36,6 +39,9 @@ def __init__(self, **data):
super().__init__(**data)
self.data = {metric.name: None for metric in self.metrics}

def __str__(self):
return f"data: {self.data}, timestamp: {self.timestamp.isoformat()}"

def update_data(self, metric_name: str, value: int):
if metric_name in self.data:
self.data[metric_name] = value
Expand Down
3 changes: 2 additions & 1 deletion src/notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
from functools import partial

from telegram.error import TimedOut
from telegram.ext import CallbackContext, JobQueue

from pyautowire import Injectable, autowire
Expand All @@ -29,7 +30,7 @@ async def reminder(self, context: CallbackContext, user_id: int, text: str = Non
@retry(
stop=stop_after_attempt(3),
wait=wait_fixed(1),
retry=retry_if_exception_type(TimeoutError),
retry=retry_if_exception_type((TimeoutError, TimedOut)),
)
async def send_from_context(context: CallbackContext, user_id: int, text: str):
"""Send a message to a user from a context."""
Expand Down
21 changes: 21 additions & 0 deletions src/repository/db_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Mechanisms for manually interacting with the database for diagnostics work etc.
"""
import logging
import os

from src.config.config import ConfigurationProvider
from src.repository.initialize import initialize_database
from src.repository.record_repository import RecordRepository
from src.repository.user_repository import UserRepository


def init() -> (UserRepository, RecordRepository):
configuration = ConfigurationProvider().get_configuration().register()
return initialize_database(configuration)


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
user_id = int(os.getenv("USER_ID"))
user_repository, record_repository = init()
15 changes: 13 additions & 2 deletions src/repository/dynamodb/dynamodb_record_repository.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import logging

import boto3
from boto3.dynamodb.conditions import Key
Expand All @@ -11,15 +12,25 @@ class DynamoDBRecordRepository(RecordRepository):
def __init__(self, dynamodb: boto3.resource):
self.table = dynamodb.Table("record")
self.table.load()
logging.info("DynamoDBRecordRepository initialized.")

def get_latest_record_for_user(self, user_id: int) -> Record | None:
result = self.get_latest_records_for_user(user_id, 1)
if result:
return result[0]

def get_latest_records_for_user(
self, user_id: int, limit: int
) -> list[Record] | None:
logging.info(f"Retrieving {limit} latest records for user {user_id}")
result = self.table.query(
KeyConditionExpression=Key("user_id").eq(user_id),
ScanIndexForward=False,
Limit=1,
Limit=limit,
)
if result.get("Items"):
return self.parse_record(result["Items"][0])
return [self.parse_record(record) for record in result["Items"]]
return []

def create_record(self, user_id: int, record_data: dict, timestamp: str):
self.table.put_item(
Expand Down
2 changes: 2 additions & 0 deletions src/repository/dynamodb/dynamodb_user_repository.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging

import boto3
from pyautowire import autowire
Expand All @@ -12,6 +13,7 @@ class DynamoDBUserRepository(UserRepository):
def __init__(self, dynamodb: boto3.resource):
self.table = dynamodb.Table("user")
self.table.load()
logging.info("DynamoDBUserRepository initialized.")

@autowire("configuration")
def create_user(self, user_id: int, configuration: Configuration) -> User:
Expand Down
8 changes: 8 additions & 0 deletions src/repository/mongodb/mongodb_record_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ def __init__(self, mongo_client: MongoClient):
super().__init__()
mood_tracker = mongo_client["mood_tracker"]
self.records = mood_tracker["records"]
logging.info("MongoDBRecordRepository initialized.")

def get_latest_records_for_user(self, user_id: int, limit: int) -> list[Record]:
result = self.records.find(
{"user_id": user_id}, sort=[("timestamp", pymongo.DESCENDING)], limit=limit
)
if result:
return [self.parse_record(r) for r in result]

def get_latest_record_for_user(self, user_id: int) -> Record | None:
result = self.records.find_one(
Expand Down
1 change: 1 addition & 0 deletions src/repository/mongodb/mongodb_user_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def __init__(self, mongo_client: MongoClient):
super().__init__()
mood_tracker = mongo_client["mood_tracker"]
self.user = mood_tracker["user"]
logging.info("MongoDBUserRepository initialized.")

def find_user(self, user_id: int) -> User | None:
result = self.user.find_one({"user_id": user_id})
Expand Down
4 changes: 4 additions & 0 deletions src/repository/record_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def modify_timestamp(timestamp: str, offset: int) -> datetime.datetime:
def get_latest_record_for_user(self, user_id: int) -> Record | None:
pass

@abstractmethod
def get_latest_records_for_user(self, user_id: int, limit: int) -> list[Record]:
pass

@abstractmethod
def create_record(self, user_id: int, record_data: dict, timestamp: str):
pass
Expand Down

0 comments on commit 7d9de86

Please sign in to comment.