2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2014-05-30 08:53:19 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2014-05-30 08:53:19 +00:00
*/
2016-03-24 13:27:34 +00:00
# include "logs.h"
2017-03-04 10:23:56 +00:00
# include "platform/platform_specific.h"
2017-12-11 14:45:29 +00:00
# include "core/crash_reports.h"
# include "core/launcher.h"
2016-01-31 18:01:43 +00:00
2019-11-14 17:03:44 +00:00
namespace {
std : : atomic < int > ThreadCounter /* = 0*/ ;
} // namespace
2016-01-11 15:43:29 +00:00
enum LogDataType {
LogDataMain ,
LogDataDebug ,
LogDataTcp ,
LogDataMtp ,
LogDataCount
} ;
2016-01-17 05:01:14 +00:00
QMutex * _logsMutex ( LogDataType type , bool clear = false ) {
static QMutex * LogsMutexes = 0 ;
if ( clear ) {
delete [ ] LogsMutexes ;
LogsMutexes = 0 ;
} else if ( ! LogsMutexes ) {
2016-01-11 15:43:29 +00:00
LogsMutexes = new QMutex [ LogDataCount ] ;
}
return & LogsMutexes [ type ] ;
}
2016-01-17 05:01:14 +00:00
2016-01-11 15:43:29 +00:00
QString _logsFilePath ( LogDataType type , const QString & postfix = QString ( ) ) {
QString path ( cWorkingDir ( ) ) ;
switch ( type ) {
2016-01-17 05:01:14 +00:00
case LogDataMain : path + = qstr ( " log " ) + postfix + qstr ( " .txt " ) ; break ;
2016-01-11 15:43:29 +00:00
case LogDataDebug : path + = qstr ( " DebugLogs/log " ) + postfix + qstr ( " .txt " ) ; break ;
case LogDataTcp : path + = qstr ( " DebugLogs/tcp " ) + postfix + qstr ( " .txt " ) ; break ;
case LogDataMtp : path + = qstr ( " DebugLogs/mtp " ) + postfix + qstr ( " .txt " ) ; break ;
}
return path ;
}
2014-05-30 08:53:19 +00:00
2016-01-17 05:01:14 +00:00
int32 LogsStartIndexChosen = - 1 ;
QString _logsEntryStart ( ) {
2019-11-14 17:03:44 +00:00
static thread_local auto threadId = ThreadCounter + + ;
static auto index = 0 ;
2016-01-17 05:01:14 +00:00
2019-11-14 17:03:44 +00:00
const auto tm = QDateTime : : currentDateTime ( ) ;
2016-01-17 05:01:14 +00:00
return QString ( " [%1 %2-%3] " ) . arg ( tm . toString ( " hh:mm:ss.zzz " ) ) . arg ( QString ( " %1 " ) . arg ( threadId , 2 , 10 , QChar ( ' 0 ' ) ) ) . arg ( + + index , 7 , 10 , QChar ( ' 0 ' ) ) ;
}
2016-01-11 15:43:29 +00:00
class LogsDataFields {
public :
2016-01-10 06:05:23 +00:00
2016-01-17 05:01:14 +00:00
LogsDataFields ( ) {
for ( int32 i = 0 ; i < LogDataCount ; + + i ) {
files [ i ] . reset ( new QFile ( ) ) ;
}
2016-01-11 15:43:29 +00:00
}
bool openMain ( ) {
2016-01-17 05:01:14 +00:00
return reopen ( LogDataMain , 0 , qsl ( " start " ) ) ;
}
2016-02-08 10:50:56 +00:00
void closeMain ( ) {
QMutexLocker lock ( _logsMutex ( LogDataMain ) ) ;
2018-06-10 07:46:15 +00:00
const auto file = files [ LogDataMain ] . get ( ) ;
if ( file & & file - > isOpen ( ) ) {
file - > close ( ) ;
2016-02-08 10:50:56 +00:00
}
}
2016-01-17 05:01:14 +00:00
bool instanceChecked ( ) {
2016-01-11 15:43:29 +00:00
return reopen ( LogDataMain , 0 , QString ( ) ) ;
2014-05-30 08:53:19 +00:00
}
2016-01-17 05:01:14 +00:00
QString full ( ) {
2018-06-10 07:46:15 +00:00
const auto file = files [ LogDataMain ] . get ( ) ;
if ( ! ! file | | ! file - > isOpen ( ) ) {
2016-01-17 05:01:14 +00:00
return QString ( ) ;
}
2018-06-10 07:46:15 +00:00
QFile out ( file - > fileName ( ) ) ;
2016-01-17 05:01:14 +00:00
if ( out . open ( QIODevice : : ReadOnly ) ) {
return QString : : fromUtf8 ( out . readAll ( ) ) ;
}
return QString ( ) ;
}
2016-01-11 15:43:29 +00:00
void write ( LogDataType type , const QString & msg ) {
QMutexLocker lock ( _logsMutex ( type ) ) ;
2018-06-10 07:46:15 +00:00
if ( type ! = LogDataMain ) {
reopenDebug ( ) ;
}
const auto file = files [ type ] . get ( ) ;
if ( ! file | | ! file - > isOpen ( ) ) {
return ;
}
file - > write ( msg . toUtf8 ( ) ) ;
file - > flush ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-01-11 15:43:29 +00:00
private :
2017-12-18 10:38:14 +00:00
std : : unique_ptr < QFile > files [ LogDataCount ] ;
2016-01-11 15:43:29 +00:00
2016-01-30 18:24:18 +00:00
int32 part = - 1 ;
2016-01-11 15:43:29 +00:00
bool reopen ( LogDataType type , int32 dayIndex , const QString & postfix ) {
2018-06-10 07:46:15 +00:00
if ( files [ type ] & & files [ type ] - > isOpen ( ) ) {
2016-01-11 15:43:29 +00:00
if ( type = = LogDataMain ) {
2016-01-17 05:01:14 +00:00
if ( ! postfix . isEmpty ( ) ) {
return true ;
}
} else {
files [ type ] - > close ( ) ;
2016-01-11 15:43:29 +00:00
}
}
2017-08-31 16:28:58 +00:00
auto mode = QIODevice : : WriteOnly | QIODevice : : Text ;
2016-01-17 05:01:14 +00:00
if ( type = = LogDataMain ) { // we can call LOG() in LogDataMain reopen - mutex not locked
if ( postfix . isEmpty ( ) ) { // instance checked, need to move to log.txt
2017-08-17 09:06:26 +00:00
Assert ( ! files [ type ] - > fileName ( ) . isEmpty ( ) ) ; // one of log_startXX.txt should've been opened already
2016-01-17 05:01:14 +00:00
2017-12-18 10:38:14 +00:00
auto to = std : : make_unique < QFile > ( _logsFilePath ( type , postfix ) ) ;
2016-01-17 05:01:14 +00:00
if ( to - > exists ( ) & & ! to - > remove ( ) ) {
LOG ( ( " Could not delete '%1' file to start new logging! " ) . arg ( to - > fileName ( ) ) ) ;
return false ;
}
if ( ! QFile ( files [ type ] - > fileName ( ) ) . copy ( to - > fileName ( ) ) ) { // don't close files[type] yet
LOG ( ( " Could not copy '%1' to '%2' to start new logging! " ) . arg ( files [ type ] - > fileName ( ) ) . arg ( to - > fileName ( ) ) ) ;
return false ;
}
if ( to - > open ( mode | QIODevice : : Append ) ) {
2017-12-18 09:07:18 +00:00
std : : swap ( files [ type ] , to ) ;
2016-01-17 05:01:14 +00:00
LOG ( ( " Moved logging from '%1' to '%2'! " ) . arg ( to - > fileName ( ) ) . arg ( files [ type ] - > fileName ( ) ) ) ;
to - > remove ( ) ;
LogsStartIndexChosen = - 1 ;
QDir working ( cWorkingDir ( ) ) ; // delete all other log_startXX.txt that we can
QStringList oldlogs = working . entryList ( QStringList ( " log_start*.txt " ) , QDir : : Files ) ;
for ( QStringList : : const_iterator i = oldlogs . cbegin ( ) , e = oldlogs . cend ( ) ; i ! = e ; + + i ) {
QString oldlog = cWorkingDir ( ) + * i , oldlogend = i - > mid ( qstr ( " log_start " ) . size ( ) ) ;
if ( oldlogend . size ( ) = = 1 + qstr ( " .txt " ) . size ( ) & & oldlogend . at ( 0 ) . isDigit ( ) & & oldlogend . midRef ( 1 ) = = qstr ( " .txt " ) ) {
bool removed = QFile ( * i ) . remove ( ) ;
LOG ( ( " Old start log '%1' found, deleted: %2 " ) . arg ( * i ) . arg ( Logs : : b ( removed ) ) ) ;
}
}
return true ;
}
LOG ( ( " Could not open '%1' file to start new logging! " ) . arg ( to - > fileName ( ) ) ) ;
return false ;
} else {
bool found = false ;
int32 oldest = - 1 ; // find not existing log_startX.txt or pick the oldest one (by lastModified)
QDateTime oldestLastModified ;
for ( int32 i = 0 ; i < 10 ; + + i ) {
QString trying = _logsFilePath ( type , qsl ( " _start%1 " ) . arg ( i ) ) ;
files [ type ] - > setFileName ( trying ) ;
if ( ! files [ type ] - > exists ( ) ) {
LogsStartIndexChosen = i ;
found = true ;
break ;
}
QDateTime lastModified = QFileInfo ( trying ) . lastModified ( ) ;
if ( oldest < 0 | | lastModified < oldestLastModified ) {
oldestLastModified = lastModified ;
oldest = i ;
}
}
if ( ! found ) {
files [ type ] - > setFileName ( _logsFilePath ( type , qsl ( " _start%1 " ) . arg ( oldest ) ) ) ;
LogsStartIndexChosen = oldest ;
}
}
} else {
files [ type ] - > setFileName ( _logsFilePath ( type , postfix ) ) ;
if ( files [ type ] - > exists ( ) ) {
if ( files [ type ] - > open ( QIODevice : : ReadOnly | QIODevice : : Text ) ) {
if ( QString : : fromUtf8 ( files [ type ] - > readLine ( ) ) . toInt ( ) = = dayIndex ) {
2016-01-11 15:43:29 +00:00
mode | = QIODevice : : Append ;
}
2016-01-17 05:01:14 +00:00
files [ type ] - > close ( ) ;
2016-01-11 15:43:29 +00:00
}
} else {
QDir ( ) . mkdir ( cWorkingDir ( ) + qstr ( " DebugLogs " ) ) ;
}
}
2016-01-17 05:01:14 +00:00
if ( files [ type ] - > open ( mode ) ) {
2016-01-11 15:43:29 +00:00
if ( type ! = LogDataMain ) {
2018-06-10 07:46:15 +00:00
files [ type ] - > write ( ( ( mode & QIODevice : : Append )
2017-12-18 09:07:18 +00:00
? qsl ( " \
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ n \
NEW LOGGING INSTANCE STARTED ! ! ! \ n \
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ n " )
2018-06-10 07:46:15 +00:00
: qsl ( " %1 \n " ) . arg ( dayIndex ) ) . toUtf8 ( ) ) ;
files [ type ] - > flush ( ) ;
2016-01-11 15:43:29 +00:00
}
return true ;
2016-01-17 05:01:14 +00:00
} else if ( type ! = LogDataMain ) {
LOG ( ( " Could not open debug log '%1'! " ) . arg ( files [ type ] - > fileName ( ) ) ) ;
2016-01-11 15:43:29 +00:00
}
return false ;
2014-05-30 08:53:19 +00:00
}
2016-01-11 15:43:29 +00:00
void reopenDebug ( ) {
time_t t = time ( NULL ) ;
struct tm tm ;
mylocaltime ( & tm , & t ) ;
static const int switchEach = 15 ; // minutes
int32 newPart = ( tm . tm_min + tm . tm_hour * 60 ) / switchEach ;
if ( newPart = = part ) return ;
part = newPart ;
int32 dayIndex = ( tm . tm_year + 1900 ) * 10000 + ( tm . tm_mon + 1 ) * 100 + tm . tm_mday ;
QString postfix = QString ( " _%4_%5 " ) . arg ( ( part * switchEach ) / 60 , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( ( part * switchEach ) % 60 , 2 , 10 , QChar ( ' 0 ' ) ) ;
reopen ( LogDataDebug , dayIndex , postfix ) ;
reopen ( LogDataTcp , dayIndex , postfix ) ;
reopen ( LogDataMtp , dayIndex , postfix ) ;
2014-05-30 08:53:19 +00:00
}
2016-01-11 15:43:29 +00:00
} ;
2014-09-30 14:11:09 +00:00
2016-01-11 15:43:29 +00:00
LogsDataFields * LogsData = 0 ;
2014-09-30 14:11:09 +00:00
2019-01-21 13:42:21 +00:00
using LogsInMemoryList = QList < QPair < LogDataType , QString > > ;
2016-01-11 15:43:29 +00:00
LogsInMemoryList * LogsInMemory = 0 ;
LogsInMemoryList * DeletedLogsInMemory = SharedMemoryLocation < LogsInMemoryList , 0 > ( ) ;
2016-01-17 05:01:14 +00:00
QString LogsBeforeSingleInstanceChecked ; // LogsInMemory already dumped in LogsData, but LogsData is about to be deleted
2016-01-11 15:43:29 +00:00
void _logsWrite ( LogDataType type , const QString & msg ) {
2016-01-17 05:01:14 +00:00
if ( LogsData & & ( type = = LogDataMain | | LogsStartIndexChosen < 0 ) ) {
2018-06-05 13:32:26 +00:00
if ( type = = LogDataMain | | Logs : : DebugEnabled ( ) ) {
2016-01-11 15:43:29 +00:00
LogsData - > write ( type , msg ) ;
}
} else if ( LogsInMemory ! = DeletedLogsInMemory ) {
if ( ! LogsInMemory ) {
LogsInMemory = new LogsInMemoryList ;
}
2016-01-17 05:01:14 +00:00
LogsInMemory - > push_back ( qMakePair ( type , msg ) ) ;
} else if ( ! LogsBeforeSingleInstanceChecked . isEmpty ( ) & & type = = LogDataMain ) {
LogsBeforeSingleInstanceChecked + = msg ;
2014-05-30 08:53:19 +00:00
}
}
2016-01-11 15:43:29 +00:00
namespace Logs {
2017-12-11 14:45:29 +00:00
namespace {
2016-01-11 15:43:29 +00:00
2018-06-05 13:32:26 +00:00
bool DebugModeEnabled = false ;
2017-12-11 14:45:29 +00:00
void MoveOldDataFiles ( const QString & wasDir ) {
2014-09-30 14:11:09 +00:00
QFile data ( wasDir + " data " ) , dataConfig ( wasDir + " data_config " ) , tdataConfig ( wasDir + " tdata/config " ) ;
if ( data . exists ( ) & & dataConfig . exists ( ) & & ! QFileInfo ( cWorkingDir ( ) + " data " ) . exists ( ) & & ! QFileInfo ( cWorkingDir ( ) + " data_config " ) . exists ( ) ) { // move to home dir
LOG ( ( " Copying data to home dir '%1' from '%2' " ) . arg ( cWorkingDir ( ) ) . arg ( wasDir ) ) ;
if ( data . copy ( cWorkingDir ( ) + " data " ) ) {
LOG ( ( " Copied 'data' to home dir " ) ) ;
if ( dataConfig . copy ( cWorkingDir ( ) + " data_config " ) ) {
LOG ( ( " Copied 'data_config' to home dir " ) ) ;
bool tdataGood = true ;
if ( tdataConfig . exists ( ) ) {
tdataGood = false ;
QDir ( ) . mkpath ( cWorkingDir ( ) + " tdata " ) ;
if ( tdataConfig . copy ( cWorkingDir ( ) + " tdata/config " ) ) {
LOG ( ( " Copied 'tdata/config' to home dir " ) ) ;
tdataGood = true ;
} else {
LOG ( ( " Copied 'data' and 'data_config', but could not copy 'tdata/config'! " ) ) ;
}
}
if ( tdataGood ) {
if ( data . remove ( ) ) {
LOG ( ( " Removed 'data' " ) ) ;
} else {
LOG ( ( " Could not remove 'data' " ) ) ;
}
if ( dataConfig . remove ( ) ) {
LOG ( ( " Removed 'data_config' " ) ) ;
} else {
LOG ( ( " Could not remove 'data_config' " ) ) ;
}
if ( ! tdataConfig . exists ( ) | | tdataConfig . remove ( ) ) {
LOG ( ( " Removed 'tdata/config' " ) ) ;
} else {
2016-10-18 07:56:38 +00:00
LOG ( ( " Could not remove 'tdata/config' " ) ) ;
2014-09-30 14:11:09 +00:00
}
QDir ( ) . rmdir ( wasDir + " tdata " ) ;
}
} else {
LOG ( ( " Copied 'data', but could not copy 'data_config'!! " ) ) ;
}
} else {
LOG ( ( " Could not copy 'data'! " ) ) ;
}
}
}
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
} // namespace
2016-03-20 09:10:16 +00:00
2018-06-05 13:32:26 +00:00
void SetDebugEnabled ( bool enabled ) {
DebugModeEnabled = enabled ;
}
bool DebugEnabled ( ) {
# if defined _DEBUG
return true ;
# else
return DebugModeEnabled ;
# endif
}
2019-06-29 12:24:46 +00:00
QString ProfilePrefix ( ) {
const auto now = crl : : profile ( ) ;
return ' [ ' + QString : : number ( now / 1000. , ' f ' , 3 ) + " ] " ;
}
2017-12-11 14:45:29 +00:00
void start ( not_null < Core : : Launcher * > launcher ) {
2019-01-21 13:42:21 +00:00
Assert ( LogsData = = nullptr ) ;
2016-01-21 06:58:58 +00:00
2019-01-21 13:42:21 +00:00
if ( ! launcher - > checkPortableVersionFolder ( ) ) {
2017-12-11 14:45:29 +00:00
return ;
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
auto initialWorkingDir = QDir ( cWorkingDir ( ) ) . absolutePath ( ) + ' / ' ;
auto moveOldDataFrom = QString ( ) ;
auto workingDirChosen = false ;
2018-09-26 14:58:09 +00:00
if ( cAlphaVersion ( ) ) {
2017-12-11 14:45:29 +00:00
workingDirChosen = true ;
2018-10-09 16:21:20 +00:00
2017-12-11 14:45:29 +00:00
# if defined Q_OS_MAC || defined Q_OS_LINUX
} else {
if ( ! cWorkingDir ( ) . isEmpty ( ) ) {
2018-10-09 16:21:20 +00:00
// This value must come from TelegramForcePortable
// or from the "-workdir" command line argument.
2017-12-11 14:45:29 +00:00
cForceWorkingDir ( cWorkingDir ( ) ) ;
} else {
2019-04-13 15:49:13 +00:00
# if defined _DEBUG && !defined OS_MAC_STORE
2018-10-09 16:21:20 +00:00
cForceWorkingDir ( cExeDir ( ) ) ;
# else // _DEBUG
2017-12-11 14:45:29 +00:00
cForceWorkingDir ( psAppDataPath ( ) ) ;
# endif // !_DEBUG
2018-10-09 16:21:20 +00:00
}
2017-12-11 14:45:29 +00:00
workingDirChosen = true ;
2016-03-20 08:16:35 +00:00
2017-12-11 14:45:29 +00:00
# if defined Q_OS_LINUX && !defined _DEBUG // fix first version
moveOldDataFrom = initialWorkingDir ;
# endif // Q_OS_LINUX && !_DEBUG
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
# elif defined Q_OS_WINRT // Q_OS_MAC || Q_OS_LINUX
} else {
cForceWorkingDir ( psAppDataPath ( ) ) ;
workingDirChosen = true ;
2018-10-09 16:21:20 +00:00
2017-12-11 14:45:29 +00:00
# elif defined OS_WIN_STORE // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT
# ifdef _DEBUG
cForceWorkingDir ( cExeDir ( ) ) ;
# else // _DEBUG
cForceWorkingDir ( psAppDataPath ( ) ) ;
# endif // !_DEBUG
workingDirChosen = true ;
2018-10-09 16:21:20 +00:00
2017-12-11 14:45:29 +00:00
# elif defined Q_OS_WIN
} else {
if ( ! cWorkingDir ( ) . isEmpty ( ) ) {
2018-10-09 16:21:20 +00:00
// This value must come from TelegramForcePortable
// or from the "-workdir" command line argument.
2017-12-11 14:45:29 +00:00
cForceWorkingDir ( cWorkingDir ( ) ) ;
workingDirChosen = true ;
2016-01-21 06:58:58 +00:00
}
2018-10-09 16:21:20 +00:00
2017-12-11 14:45:29 +00:00
# endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || OS_WIN_STORE
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
LogsData = new LogsDataFields ( ) ;
if ( ! workingDirChosen ) {
cForceWorkingDir ( cExeDir ( ) ) ;
if ( ! LogsData - > openMain ( ) ) {
cForceWorkingDir ( psAppDataPath ( ) ) ;
2016-03-31 11:55:25 +00:00
}
}
2017-12-11 14:45:29 +00:00
cForceWorkingDir ( QDir ( cWorkingDir ( ) ) . absolutePath ( ) + ' / ' ) ;
2016-03-31 11:55:25 +00:00
2017-12-11 14:45:29 +00:00
// WinRT build requires the working dir to stay the same for plugin loading.
# ifndef Q_OS_WINRT
QDir ( ) . setCurrent ( cWorkingDir ( ) ) ;
# endif // !Q_OS_WINRT
2016-03-31 11:55:25 +00:00
2017-12-11 14:45:29 +00:00
QDir ( ) . mkpath ( cWorkingDir ( ) + qstr ( " tdata " ) ) ;
2016-01-25 10:22:58 +00:00
2019-01-21 13:42:21 +00:00
launcher - > workingFolderReady ( ) ;
CrashReports : : StartCatching ( launcher ) ;
2016-01-25 10:22:58 +00:00
2017-12-11 14:45:29 +00:00
if ( ! LogsData - > openMain ( ) ) {
delete LogsData ;
2019-01-21 13:42:21 +00:00
LogsData = nullptr ;
2016-01-30 18:38:33 +00:00
}
2018-09-26 15:11:16 +00:00
LOG ( ( " Launched version: %1, "
" install beta: %2, "
" alpha: %3, "
" debug mode: %4, "
" test dc: %5 "
) . arg ( AppVersion
) . arg ( Logs : : b ( cInstallBetaVersion ( ) )
) . arg ( cAlphaVersion ( )
) . arg ( Logs : : b ( DebugEnabled ( ) )
) . arg ( Logs : : b ( cTestMode ( ) ) ) ) ;
2017-12-11 14:45:29 +00:00
LOG ( ( " Executable dir: %1, name: %2 " ) . arg ( cExeDir ( ) ) . arg ( cExeName ( ) ) ) ;
LOG ( ( " Initial working dir: %1 " ) . arg ( initialWorkingDir ) ) ;
LOG ( ( " Working dir: %1 " ) . arg ( cWorkingDir ( ) ) ) ;
LOG ( ( " Command line: %1 " ) . arg ( launcher - > argumentsString ( ) ) ) ;
2016-01-25 10:22:58 +00:00
2017-12-11 14:45:29 +00:00
if ( ! LogsData ) {
2018-09-26 15:11:16 +00:00
LOG ( ( " FATAL: Could not open '%1' for writing log! "
) . arg ( _logsFilePath ( LogDataMain , qsl ( " _startXX " ) ) ) ) ;
2017-12-11 14:45:29 +00:00
return ;
2016-01-30 18:24:18 +00:00
}
2017-12-11 14:45:29 +00:00
# ifdef Q_OS_WIN
if ( cWorkingDir ( ) = = psAppDataPath ( ) ) { // fix old "Telegram Win (Unofficial)" version
moveOldDataFrom = psAppDataPathOld ( ) ;
2016-09-29 11:37:16 +00:00
}
2016-01-31 11:32:29 +00:00
# endif
2017-12-11 14:45:29 +00:00
if ( ! moveOldDataFrom . isEmpty ( ) ) {
MoveOldDataFiles ( moveOldDataFrom ) ;
}
2016-01-31 11:32:29 +00:00
2017-12-11 14:45:29 +00:00
if ( LogsInMemory ) {
Assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
LogsInMemoryList list = * LogsInMemory ;
for ( LogsInMemoryList : : const_iterator i = list . cbegin ( ) , e = list . cend ( ) ; i ! = e ; + + i ) {
if ( i - > first = = LogDataMain ) {
_logsWrite ( i - > first , i - > second ) ;
2016-01-31 11:32:29 +00:00
}
}
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
LOG ( ( " Logs started " ) ) ;
}
2016-02-01 10:12:37 +00:00
2017-12-11 14:45:29 +00:00
void finish ( ) {
delete LogsData ;
LogsData = 0 ;
2016-03-14 09:25:48 +00:00
2017-12-11 14:45:29 +00:00
if ( LogsInMemory & & LogsInMemory ! = DeletedLogsInMemory ) {
delete LogsInMemory ;
2016-02-01 10:12:37 +00:00
}
2017-12-11 14:45:29 +00:00
LogsInMemory = DeletedLogsInMemory ;
2016-03-20 09:10:16 +00:00
2017-12-11 14:45:29 +00:00
_logsMutex ( LogDataMain , true ) ;
2016-02-01 10:12:37 +00:00
2017-12-11 14:45:29 +00:00
CrashReports : : FinishCatching ( ) ;
}
2016-03-31 11:55:25 +00:00
2017-12-11 14:45:29 +00:00
bool started ( ) {
return LogsData ! = 0 ;
}
2016-03-31 11:55:25 +00:00
2017-12-11 14:45:29 +00:00
bool instanceChecked ( ) {
if ( ! LogsData ) return false ;
2016-02-02 11:48:46 +00:00
2017-12-11 14:45:29 +00:00
if ( ! LogsData - > instanceChecked ( ) ) {
LogsBeforeSingleInstanceChecked = Logs : : full ( ) ;
2016-02-01 10:12:37 +00:00
2017-12-11 14:45:29 +00:00
delete LogsData ;
LogsData = 0 ;
LOG ( ( " FATAL: Could not move logging to '%1'! " ) . arg ( _logsFilePath ( LogDataMain ) ) ) ;
return false ;
2016-02-01 10:12:37 +00:00
}
2017-12-11 14:45:29 +00:00
if ( LogsInMemory ) {
Assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
LogsInMemoryList list = * LogsInMemory ;
for ( LogsInMemoryList : : const_iterator i = list . cbegin ( ) , e = list . cend ( ) ; i ! = e ; + + i ) {
if ( i - > first ! = LogDataMain ) {
_logsWrite ( i - > first , i - > second ) ;
}
2016-02-01 10:12:37 +00:00
}
2017-12-11 14:45:29 +00:00
}
if ( LogsInMemory ) {
Assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
delete LogsInMemory ;
}
LogsInMemory = DeletedLogsInMemory ;
DEBUG_LOG ( ( " Debug logs started. " ) ) ;
LogsBeforeSingleInstanceChecked . clear ( ) ;
return true ;
}
2016-03-20 09:10:16 +00:00
2017-12-11 14:45:29 +00:00
void multipleInstances ( ) {
if ( LogsInMemory ) {
Assert ( LogsInMemory ! = DeletedLogsInMemory ) ;
delete LogsInMemory ;
2016-02-01 10:12:37 +00:00
}
2017-12-11 14:45:29 +00:00
LogsInMemory = DeletedLogsInMemory ;
2016-02-01 10:12:37 +00:00
2018-06-05 13:32:26 +00:00
if ( Logs : : DebugEnabled ( ) ) {
2017-12-11 14:45:29 +00:00
LOG ( ( " WARNING: debug logs are not written in multiple instances mode! " ) ) ;
}
LogsBeforeSingleInstanceChecked . clear ( ) ;
}
2016-03-20 09:10:16 +00:00
2017-12-11 14:45:29 +00:00
void closeMain ( ) {
LOG ( ( " Explicitly closing main log and finishing crash handlers. " ) ) ;
if ( LogsData ) {
LogsData - > closeMain ( ) ;
}
}
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
void writeMain ( const QString & v ) {
time_t t = time ( NULL ) ;
struct tm tm ;
mylocaltime ( & tm , & t ) ;
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
QString msg ( QString ( " [%1.%2.%3 %4:%5:%6] %7 \n " ) . arg ( tm . tm_year + 1900 ) . arg ( tm . tm_mon + 1 , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_mday , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_hour , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_min , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( tm . tm_sec , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( v ) ) ;
_logsWrite ( LogDataMain , msg ) ;
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
QString debugmsg ( QString ( " %1 %2 \n " ) . arg ( _logsEntryStart ( ) ) . arg ( v ) ) ;
_logsWrite ( LogDataDebug , debugmsg ) ;
}
2016-03-20 09:10:16 +00:00
2017-12-11 14:45:29 +00:00
void writeDebug ( const char * file , int32 line , const QString & v ) {
const char * last = strstr ( file , " / " ) , * found = 0 ;
while ( last ) {
found = last ;
last = strstr ( last + 1 , " / " ) ;
}
last = strstr ( file , " \\ " ) ;
while ( last ) {
found = last ;
last = strstr ( last + 1 , " \\ " ) ;
}
if ( found ) {
file = found + 1 ;
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
QString msg ( QString ( " %1 %2 (%3 : %4) \ n " ).arg(_logsEntryStart()).arg(v).arg(file).arg(line)) ;
_logsWrite ( LogDataDebug , msg ) ;
2016-01-30 16:31:10 +00:00
2016-02-09 16:05:08 +00:00
# ifdef Q_OS_WIN
2017-12-11 14:45:29 +00:00
//OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
# elif defined Q_OS_MAC
//objc_outputDebugString(msg);
# elif defined Q_OS_LINUX && defined _DEBUG
//std::cout << msg.toUtf8().constData();
# endif
}
2016-09-29 11:37:16 +00:00
2017-12-11 14:45:29 +00:00
void writeTcp ( const QString & v ) {
QString msg ( QString ( " %1 %2 \n " ) . arg ( _logsEntryStart ( ) ) . arg ( v ) ) ;
_logsWrite ( LogDataTcp , msg ) ;
}
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
void writeMtp ( int32 dc , const QString & v ) {
QString msg ( QString ( " %1 (dc:%2) % 3 \ n " ).arg(_logsEntryStart()).arg(dc).arg(v)) ;
_logsWrite ( LogDataMtp , msg ) ;
}
2016-01-21 06:58:58 +00:00
2017-12-11 14:45:29 +00:00
QString full ( ) {
if ( LogsData ) {
return LogsData - > full ( ) ;
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
if ( ! LogsInMemory | | LogsInMemory = = DeletedLogsInMemory ) {
return LogsBeforeSingleInstanceChecked ;
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
int32 size = LogsBeforeSingleInstanceChecked . size ( ) ;
for ( LogsInMemoryList : : const_iterator i = LogsInMemory - > cbegin ( ) , e = LogsInMemory - > cend ( ) ; i ! = e ; + + i ) {
if ( i - > first = = LogDataMain ) {
size + = i - > second . size ( ) ;
2016-03-14 09:25:48 +00:00
}
}
2017-12-11 14:45:29 +00:00
QString result ;
result . reserve ( size ) ;
if ( ! LogsBeforeSingleInstanceChecked . isEmpty ( ) ) {
result . append ( LogsBeforeSingleInstanceChecked ) ;
}
for ( LogsInMemoryList : : const_iterator i = LogsInMemory - > cbegin ( ) , e = LogsInMemory - > cend ( ) ; i ! = e ; + + i ) {
if ( i - > first = = LogDataMain ) {
result + = i - > second ;
2016-03-31 11:55:25 +00:00
}
2016-03-15 12:18:12 +00:00
}
2017-12-11 14:45:29 +00:00
return result ;
2016-01-21 06:58:58 +00:00
}
2017-12-11 14:45:29 +00:00
} // namespace Logs