Commit 2da189c8 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Add external logging support

parent cd1d1571
#pragma once
#include <string>
class ILogger
{
public:
virtual ~ILogger() = default;
virtual void Error( const std::string& msg ) = 0;
virtual void Warning( const std::string& msg ) = 0;
virtual void Info( const std::string& msg ) = 0;
};
......@@ -75,6 +75,7 @@ class IMediaLibrary
*/
virtual void discover( const std::string& entryPoint ) = 0;
virtual const std::string& snapshotPath() const = 0;
virtual void setLogger( ILogger* logger ) = 0;
};
class MediaLibraryFactory
......
......@@ -15,6 +15,7 @@ class IMovie;
class IShow;
class IShowEpisode;
class IVideoTrack;
class ILogger;
struct sqlite3;
......
......@@ -2,6 +2,7 @@
#include "Album.h"
#include "File.h"
#include "database/SqliteTools.h"
#include "logging/Logger.h"
const std::string policy::AlbumTrackTable::Name = "AlbumTrack";
const std::string policy::AlbumTrackTable::CacheColumn = "id_track";
......@@ -97,7 +98,7 @@ bool AlbumTrack::destroy()
// Manually remove Files from cache, and let foreign key handling delete them from the DB
auto fs = files();
if ( fs.size() == 0 )
std::cerr << "No files found for AlbumTrack " << m_id << std::endl;
Log::Warning( "No files found for AlbumTrack ", m_id );
for ( auto& f : fs )
{
// Ignore failures to discard from cache, we might want to discard records from
......
......@@ -32,8 +32,8 @@ list(APPEND HEADERS_LIST
${CMAKE_SOURCE_DIR}/include/IDiscoverer.h
${CMAKE_SOURCE_DIR}/include/filesystem/IDirectory.h
${CMAKE_SOURCE_DIR}/include/filesystem/IFile.h
${CMAKE_SOURCE_DIR}/include/factory/IFileSystem.h
${CMAKE_SOURCE_DIR}/include/ILogger.h
database/Cache.h
database/SqliteTools.h
......@@ -72,6 +72,9 @@ list(APPEND SRC_LIST ${HEADERS_LIST}
discoverer/FsDiscoverer.cpp
Utils.cpp
logging/IostreamLogger.cpp
logging/Logger.cpp
)
if (${EMOTION_FOUND})
......
......@@ -9,6 +9,7 @@
#include "File.h"
#include "Folder.h"
#include "Label.h"
#include "logging/Logger.h"
#include "Movie.h"
#include "ShowEpisode.h"
#include "database/SqliteTools.h"
......@@ -312,7 +313,7 @@ bool File::addLabel( LabelPtr label )
{
if ( m_id == 0 || label->id() == 0 )
{
std::cerr << "Both file & label need to be inserted in database before being linked together" << std::endl;
Log::Error( "Both file & label need to be inserted in database before being linked together" );
return false;
}
const char* req = "INSERT INTO LabelFileRelation VALUES(?, ?)";
......@@ -323,7 +324,7 @@ bool File::removeLabel( LabelPtr label )
{
if ( m_id == 0 || label->id() == 0 )
{
std::cerr << "Can't unlink a label/file not inserted in database" << std::endl;
Log::Error( "Can't unlink a label/file not inserted in database" );
return false;
}
const char* req = "DELETE FROM LabelFileRelation WHERE id_label = ? AND id_file = ?";
......
......@@ -8,6 +8,7 @@
#include "MediaLibrary.h"
#include "IMetadataService.h"
#include "Label.h"
#include "logging/Logger.h"
#include "Movie.h"
#include "Parser.h"
#include "Show.h"
......@@ -96,7 +97,10 @@ bool MediaLibrary::initialize( const std::string& dbPath, const std::string& sna
return false;
m_dbConnection.reset( dbConnection, &sqlite3_close );
if ( sqlite::Tools::executeRequest( DBConnection(m_dbConnection), "PRAGMA foreign_keys = ON" ) == false )
{
Log::Error( "Failed to enable foreign keys" );
return false;
}
if ( ! ( File::createTable( m_dbConnection ) &&
Folder::createTable( m_dbConnection ) &&
Label::createTable( m_dbConnection ) &&
......@@ -108,7 +112,7 @@ bool MediaLibrary::initialize( const std::string& dbPath, const std::string& sna
VideoTrack::createTable( m_dbConnection ) &&
AudioTrack::createTable( m_dbConnection ) ) )
{
std::cerr << "Failed to create database structure" << std::endl;
Log::Error( "Failed to create database structure" );
return false;
}
return loadFolders();
......@@ -254,6 +258,11 @@ const std::string& MediaLibrary::snapshotPath() const
return m_snapshotPath;
}
void MediaLibrary::setLogger( ILogger* logger )
{
Log::SetLogger( logger );
}
bool MediaLibrary::loadFolders()
{
//FIXME: This should probably be in a sql transaction
......@@ -363,7 +372,7 @@ FilePtr MediaLibrary::addFile( const fs::IFile* file, unsigned int folderId )
auto fptr = File::create( m_dbConnection, file, folderId );
if ( fptr == nullptr )
{
std::cerr << "Failed to add file " << file->fullPath() << " to the media library" << std::endl;
Log::Error( "Failed to add file ", file->fullPath(), " to the media library" );
return nullptr;
}
// Keep in mind that this is queued by the parser thread, there is no waranty about
......
......@@ -7,6 +7,7 @@ class Parser;
#include "IMediaLibrary.h"
#include "IDiscoverer.h"
#include "logging/Logger.h"
class MediaLibrary : public IMediaLibrary, public IDiscovererCb
{
......@@ -44,6 +45,7 @@ class MediaLibrary : public IMediaLibrary, public IDiscovererCb
virtual FilePtr onNewFile(const fs::IFile* file, FolderPtr parent ) override;
virtual const std::string& snapshotPath() const override;
virtual void setLogger( ILogger* logger ) override;
private:
static const std::vector<std::string> supportedExtensions;
......
......@@ -10,6 +10,7 @@
#include <iostream>
#include "Types.h"
#include "logging/Logger.h"
namespace sqlite
{
......@@ -196,8 +197,8 @@ class Tools
int res = sqlite3_prepare_v2( dbConnection.get(), req.c_str(), -1, &stmt, NULL );
if ( res != SQLITE_OK )
{
std::cerr << "Failed to execute request: " << req << std::endl;
std::cerr << sqlite3_errmsg( dbConnection.get() ) << std::endl;
Log::Error( "Failed to execute request: ", req,
sqlite3_errmsg( dbConnection.get() ) );
}
return StmtPtr( stmt, &sqlite3_finalize );
}
......@@ -223,14 +224,13 @@ class Tools
} while ( res == SQLITE_ROW );
if ( res != SQLITE_DONE )
{
std::cerr << "Failed to execute <" << req << '>' << std::endl;
std::cerr << "Invalid result: " <<
Log::Error( "Failed to execute <", req, ">\nInvalid result: ",
#if SQLITE_VERSION_NUMBER >= 3007015
sqlite3_errstr( res )
#else
res
#endif
<< ": " << sqlite3_errmsg( dbConnection.get() ) << std::endl;
, ": ", sqlite3_errmsg( dbConnection.get() ) );
return false;
}
return true;
......
#pragma once
#include <ILogger.h>
#include <iostream>
class IostreamLogger : public ILogger
{
public:
virtual void Error(const std::string& msg)
{
std::cout << "Error: " << msg;
}
virtual void Warning(const std::string& msg)
{
std::cout << "Warning: " << msg;
}
virtual void Info(const std::string& msg)
{
std::cout << "Info: " << msg;
}
};
#include "Logger.h"
#include "logging/IostreamLogger.h"
std::unique_ptr<ILogger> Log::s_defaultLogger = std::unique_ptr<ILogger>( new IostreamLogger );
std::atomic<ILogger*> Log::s_logger;
#pragma once
#include <atomic>
#include <memory>
#include <sstream>
#include "ILogger.h"
class Log
{
private:
enum class Level
{
Error,
Warning,
Info,
};
template <typename T>
static void createMsg( std::stringstream& s, T&& t )
{
s << t;
}
template <typename T, typename... Args>
static void createMsg( std::stringstream& s, T&& t, Args&&... args )
{
s << std::forward<T>( t );
createMsg( s, std::forward<Args>( args )... );
}
template <typename... Args>
static std::string createMsg( Args&&... args )
{
std::stringstream stream;
createMsg( stream, std::forward<Args>( args )... );
stream << "\n";
return stream.str();
}
template <typename... Args>
static void log(Level lvl, Args&&... args)
{
auto msg = createMsg( std::forward<Args>( args )... );
auto l = s_logger.load( std::memory_order_consume );
if ( l == nullptr )
l = s_defaultLogger.get();
switch ( lvl )
{
case Level::Error:
l->Error( msg );
break;
case Level::Warning:
l->Warning( msg );
break;
case Level::Info:
l->Info( msg );
break;
}
}
public:
static void SetLogger( ILogger* logger )
{
s_logger.store( logger, std::memory_order_relaxed );
}
template <typename... Args>
static void Error( Args... args )
{
log( Level::Error, std::forward<Args>( args )... );
}
template <typename... Args>
static void Warning( Args... args )
{
log( Level::Warning, std::forward<Args>( args )... );
}
template <typename... Args>
static void Info( Args... args )
{
log( Level::Info, std::forward<Args>( args )... );
}
private:
private:
static std::unique_ptr<ILogger> s_defaultLogger;
static std::atomic<ILogger*> s_logger;
};
......@@ -67,7 +67,7 @@ ServiceStatus VLCMetadataService::handleMediaMeta( FilePtr file, VLC::Media& med
auto tracks = media.tracks();
if ( tracks.size() == 0 )
{
std::cerr << "Failed to fetch tracks" << std::endl;
Log::Error( "Failed to fetch tracks" );
return StatusFatal;
}
bool isAudio = true;
......@@ -115,14 +115,14 @@ bool VLCMetadataService::parseAudioFile( FilePtr file, VLC::Media& media ) const
album = m_ml->createAlbum( albumTitle );
if ( album == nullptr )
{
std::cerr << "Failed to create/get album" << std::endl;
Log::Error( "Failed to create/get album" );
return false;
}
auto trackNbStr = media.meta( libvlc_meta_TrackNumber );
if ( trackNbStr.length() == 0 )
{
std::cerr << "Failed to get track id" << std::endl;
Log::Error( "Failed to get track id" );
return false;
}
auto artwork = media.meta( libvlc_meta_ArtworkURL );
......@@ -132,7 +132,7 @@ bool VLCMetadataService::parseAudioFile( FilePtr file, VLC::Media& media ) const
auto title = media.meta( libvlc_meta_Title );
if ( title.length() == 0 )
{
std::cerr << "Failed to compute track title" << std::endl;
Log::Error( "Failed to compute track title" );
title = "Unknown track #";
title += trackNbStr;
}
......@@ -140,7 +140,7 @@ bool VLCMetadataService::parseAudioFile( FilePtr file, VLC::Media& media ) const
auto track = album->addTrack( title, trackNb );
if ( track == nullptr )
{
std::cerr << "Failure while creating album track" << std::endl;
Log::Error( "Failure while creating album track" );
return false;
}
file->setAlbumTrack( track );
......@@ -179,7 +179,7 @@ bool VLCMetadataService::parseVideoFile( FilePtr file, VLC::Media& media ) const
int episodeId = std::stoi( episodeIdStr, &endpos );
if ( endpos != episodeIdStr.length() )
{
std::cerr << "Invalid episode id provided" << std::endl;
Log::Error( "Invalid episode id provided" );
return true;
}
show->addEpisode( title, episodeId );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment