Skip to content

Commit

Permalink
Closes #20. Added a Logger class to unify and standarize logging
Browse files Browse the repository at this point in the history
  • Loading branch information
paurieraf committed May 21, 2019
1 parent 750b67d commit 2bdeffb
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 71 deletions.
60 changes: 60 additions & 0 deletions app/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import logging
from enum import Enum

from app import models

logger = logging.getLogger(__name__)


class Logger:
class DBOperation:
CREATE = 'Create'
UPDATE = 'Update'
DELETE = 'Delete'

@staticmethod
def log_command(command, command_args, update):
user = update.message.from_user
chat = update.message.chat

logger.info(f'Command: "{command.value}". Args: "{", ".join(command_args)}". '
f'User: "{user.id} ({user.username or ""})". Chat: "{chat.id} ({chat.title or ""})"')

@staticmethod
def log_inline(command, update):
user = update.inline_query.from_user
query = update.inline_query.query

logger.info(f'Inline: "{command.value}". Query: "{query}". '
f'User: "{user.id} ({user.username or ""})"')

@staticmethod
def log_url_processing(url, is_valid, update):
user = update.message.from_user
chat = update.message.chat

logger.info(
f'URL: "{url}". Valid: "{is_valid}". '
f'User: "{user.id} ({user.username or ""})". Chat: "{chat.id} ({chat.title or ""})"')

@staticmethod
def log_db_operation(db_operation, entity):

if isinstance(entity, models.Link):
msg = f'{db_operation}. Link: "{entity.url}". Type: "{entity.link_type}". ' \
f'User: "{entity.user.id} ({entity.user.username or ""}"). ' \
f'Chat: {entity.chat.id} ({entity.chat.name or ""})'
elif isinstance(entity, models.User):
msg = f'{db_operation}. User: "{entity.id} ({entity.username or entity.first_name or ""}")'
elif isinstance(entity, models.Chat):
msg = f'{db_operation}. Chat: "{entity.id} ({entity.name})"'
elif isinstance(entity, models.Artist):
msg = f'{db_operation}. Artist: "{entity.name}"'
elif isinstance(entity, models.Album):
msg = f'{db_operation}. Album: "{entity.name}". Artist: "{entity.artists.first().name or ""}"'
elif isinstance(entity, models.Track):
msg = f'{db_operation}. Track: "{entity.name}". Artist: "{entity.artists.first().name or ""}"'
elif isinstance(entity, models.Genre):
msg = f'{db_operation}. Genre: "{entity}"'

logger.info(msg)
111 changes: 40 additions & 71 deletions app/music_bucket_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from peewee import fn, SQL
from telegram import InlineQueryResultArticle, InputTextMessageContent

from app.logger import Logger
from app.models import User, Chat, Link, Track, Artist, Album, Genre, LastFMUsername
from app.music.lastfm import LastFMClient
from app.music.music import LinkType, EntityType
Expand Down Expand Up @@ -89,15 +90,15 @@ def _handle(bot, update, command, command_args=[]):


class MusicBucketBot:
"""Command executor"""
"""Command executor. Logic core."""

class LinkProcessor:
def extract_url_from_message(self, text):
"""Gets the first url of a message"""
link = re.search("(?P<url>https?://[^\s]+)", text)
if link is not None:
logger.info(f'Extracting url from message: {text}')
return link.group('url')
url = link.group('url')
return url
return ''

def __init__(self, *args, **kwargs):
Expand All @@ -113,9 +114,13 @@ def __init__(self, *args, **kwargs):
self.responser = Responser(self.bot, self.update)

def execute_search(self):
Logger.log_inline(self.command, self.update)

self._search()

def execute_command(self):
Logger.log_command(self.command, self.command_args, self.update)

if self.command == Commands.MUSIC:
self._music()
elif self.command == Commands.MUSIC_FROM_BEGINNING:
Expand Down Expand Up @@ -156,9 +161,6 @@ def _music(self):

self.responser.reply_music(last_week_links)

logger.info(
f"'/music' command was called by user {self.update.message.from_user.id} in chat {self.update.message.chat_id}")

def _music_from_beginning(self):
"""
Command /music_from_beginning @username
Expand Down Expand Up @@ -188,9 +190,6 @@ def _music_from_beginning(self):
all_time_links = dict(all_time_links)

self.responser.reply_music_from_beginning(all_time_links)
logger.info(
f"'/music_from_beginning' command was called by user {self.update.message.from_user.id} \
in chat {self.update.message.chat_id} for the user {username}")

def _recommendations(self):
"""
Expand Down Expand Up @@ -218,9 +217,6 @@ def _recommendations(self):
track_recommendations = self.spotify_client.get_recommendations(artist_seeds)
self.responser.reply_recommendations(track_recommendations, artist_seeds)

logger.info(f"'/recommendations' command was called by user {self.update.message.from_user.id} "
f"in the chat {self.update.message.chat_id}")

def _now_playing(self):
"""
Command /np
Expand All @@ -238,10 +234,6 @@ def _now_playing(self):

self.responser.reply_now_playing(now_playing, username)

logger.info(
f"'/np' command was called by user {self.update.message.from_user.id} "
f"in the chat {self.update.message.chat_id}")

def _lastfmset_username(self):
"""
Command /lastfmset
Expand All @@ -266,10 +258,6 @@ def _lastfmset_username(self):

self.responser.reply_lastfmset(username)

logger.info(
f"'/lastfmset' command was called by user {self.update.message.from_user.id} "
f"in the chat {self.update.message.chat_id}")

def _stats(self):
"""
Command /stats
Expand All @@ -284,10 +272,6 @@ def _stats(self):

self.responser.reply_stats(users)

logger.info(
f"'/stats' command was called by user {self.update.message.from_user.id} "
f"in the chat {self.update.message.chat_id}")

def _search(self):
results = []

Expand All @@ -305,7 +289,6 @@ def _search(self):
valid_entity_type = True

if valid_entity_type and len(query) >= 3:
logger.info(f"Searching for entity:'{entity_type}' with query:'{query}'")
search_result = self.spotify_client.search_link(query, entity_type)
for result in search_result:
thumb_url = ''
Expand Down Expand Up @@ -343,11 +326,12 @@ def process_message(self):
"""
url = self.link_processor.extract_url_from_message(self.update.message.text)
link_type = self.spotify_client.get_link_type(url)
if not self.spotify_client.is_valid_url(url):
return
if not link_type:
return
self._process_url(url, link_type)
if url:
if not self.spotify_client.is_valid_url(url) or not link_type:
Logger.log_url_processing(url, False, self.update)
return
Logger.log_url_processing(url, True, self.update)
self._process_url(url, link_type)

def _process_url(self, url, link_type):
cleaned_url = self.spotify_client.clean_url(url)
Expand All @@ -356,7 +340,7 @@ def _process_url(self, url, link_type):
chat = self._save_chat()

# Create or update the link
link, updated = self._save_link(cleaned_url, link_type, user, chat)
link, was_updated = self._save_link(cleaned_url, link_type, user, chat)

if link_type == LinkType.ARTIST:
spotify_artist = self.spotify_client.client.artist(entity_id)
Expand All @@ -374,13 +358,12 @@ def _process_url(self, url, link_type):
link.track = track
link.save()

self.responser.reply_save_link(link, spotify_track, updated)
self.responser.reply_save_link(link, spotify_track, was_updated)

# Operations
def _save_artist(self, spotify_artist):
logger.info(f"Saving the artist: {spotify_artist['name']}")
# Save or retrieve the artist
saved_artist, created = Artist.get_or_create(
saved_artist, was_created = Artist.get_or_create(
id=spotify_artist['id'],
defaults={
'name': spotify_artist['name'],
Expand All @@ -391,16 +374,15 @@ def _save_artist(self, spotify_artist):
'uri': spotify_artist['uri']})

# Save or retrieve the genres
if created:
logger.info(f'Saving genres for artist {saved_artist.name}')
if was_created:
saved_genres = self._save_genres(spotify_artist['genres'])
saved_artist.genres = saved_genres
saved_artist.save()
Logger.log_db_operation(Logger.DBOperation.CREATE, saved_artist)
return saved_artist

def _save_album(self, spotify_album):
logger.info(f"Saving the album: {spotify_album['name']}")
saved_album, created = Album.get_or_create(
saved_album, was_created = Album.get_or_create(
id=spotify_album['id'],
defaults={
'name': spotify_album['name'],
Expand All @@ -411,35 +393,30 @@ def _save_album(self, spotify_album):
'spotify_url': spotify_album['external_urls']['spotify'],
'uri': spotify_album['uri']})

if created:
if was_created:
saved_artists = []
logger.info(f"Saving artists for album: {spotify_album['name']}")
for album_artist in spotify_album['artists']:
artist_id = album_artist['id']
artist = self.spotify_client.client.artist(artist_id)
saved_artist = self._save_artist(artist)
saved_artists.append(saved_artist)
logger.info(f"Saved artist {saved_artist.name}")
# Set the artists to the album
saved_album.artists = saved_artist
saved_album.save()
# Save the genres
logger.info(f"Saving genres for album {saved_album.name} with id {saved_album.id}")

saved_genres = self._save_genres(spotify_album['genres'])
saved_album.genres = saved_genres
saved_album.save()
Logger.log_db_operation(Logger.DBOperation.CREATE, saved_album)
return saved_album

def _save_track(self, spotify_track):
logger.info(f"Saving the track: {spotify_track['name']}")
# Save the album
logger.info(f"Saving the album for track {spotify_track['name']} with id {spotify_track['id']}")
album_id = spotify_track['album']['id']
album = self.spotify_client.client.album(album_id)
saved_album = self._save_album(album)

# Save the track (with the album)
saved_track, created = Track.get_or_create(
saved_track, was_created = Track.get_or_create(
id=spotify_track['id'],
defaults={
'name': spotify_track['name'],
Expand All @@ -453,75 +430,67 @@ def _save_track(self, spotify_track):
'uri': spotify_track['uri'],
'album': saved_album})

if created:
if was_created:
saved_artists = []
logger.info(f"Saving artists for track {saved_track.name} with id {saved_track.id}")
for track_artist in spotify_track['artists']:
artist_id = track_artist['id']
artist = self.spotify_client.client.artist(artist_id)
saved_artist = self._save_artist(artist)
saved_artists.append(saved_artist)
logger.info(f"Saved artist {saved_artist.name}")
# Set the artists to the album
saved_track.artists = saved_artists
saved_track.save()
Logger.log_db_operation(Logger.DBOperation.CREATE, saved_track)
return saved_track

def _save_genres(self, genres):
saved_genres = []
for genre in genres:
saved_genre, created = Genre.get_or_create(name=genre)
saved_genre, was_created = Genre.get_or_create(name=genre)
saved_genres.append(saved_genre)
logger.info(f'Saved genre {saved_genre.name}')
if was_created:
Logger.log_db_operation(Logger.DBOperation.CREATE, saved_genre)
return saved_genres

def _save_user(self):
# Create or get the user that sent the link
user, user_created = User.get_or_create(
user, was_created = User.get_or_create(
id=self.update.message.from_user.id,
defaults={
'username': self.update.message.from_user.username,
'first_name': self.update.message.from_user.first_name})

if user_created:
logger.info("User '{}' with id '{}' was created".format(
user.username if user.username else user.first_name,
user.id))
if was_created:
Logger.log_db_operation(Logger.DBOperation.CREATE, user)
return user

def _save_chat(self):
# Create or get the chat where the link was sent
chat, chat_created = Chat.get_or_create(
chat, was_created = Chat.get_or_create(
id=self.update.message.chat_id,
defaults={
'name': self.update.message.chat.title or self.update.message.chat.username or self.update.message.chat.first_name
})
if chat_created:
logger.info(f"Chat '{chat.name}' with id '{chat.id}' was created")

if was_created:
Logger.log_db_operation(Logger.DBOperation.CREATE, chat)
return chat

def _save_link(self, cleaned_url, link_type, user, chat):
# Update the link if it exists for a chat, create if it doesn't exist
link = Link.get_or_none((Link.url == cleaned_url) & (Link.chat == chat))
link_updated = False
was_updated = False
if link is not None:
# If link already exists, set updated_at and last_update_user to current
link.apply_update(user)
link.save()
link_updated = True
was_updated = True
Logger.log_db_operation(Logger.DBOperation.UPDATE, link)
else:
link = Link.create(
url=cleaned_url,
link_type=link_type.value,
created_at=datetime.datetime.now(),
user=user,
chat=chat)
Logger.log_db_operation(Logger.DBOperation.CREATE, link)

# Log link operation
link_operation = 'Saved' if not link_updated else 'Updated'

logger.info("'{}' link '{}' of type '{}' in chat '{}'".format(
link_operation, link.url, link.link_type, link.chat.name))

return link, link_updated
return link, was_updated

0 comments on commit 2bdeffb

Please sign in to comment.