Логи для экспертов

 
Хотелось бы, чтобы по каждому эксперту велись логи, в которые бы попадало все, что отправляется через функцию Print() или новую Log().

Сейчас вывод разных экспертов и индикаторов идет в перемешку на вкладке Experts, что черезвычайно затрудняет анализ. Перезапустился терминал, перегрузилась машина и все сообщения утеряны, а хотелось бы чтобы в папке logs были файлы вида Expertname_Symbol_Period_YYMMDD.log, в котором мы хранился весь вывод эксперта для данного символа и периода за день.

Я написал простой logger, который делает это, но не нашел возможности дописывать информацию в файл, поэтому при каждом запуске эксперта создается новый лог-файл, логов становится больше, но информация не теряется.
#include <stdlib.mqh>

int LogFileHandle = -1;

string getDefaultLogName(string id) {
    string t = TimeToStr(LocalTime(), TIME_DATE|TIME_SECONDS);
    t = StringReplace(t, ':', '_');
    t = StringReplace(t, ' ', '_');
    
    string logFileName = id + Symbol() + "_" + Period() + 
    "_" + t + ".txt";
    
    return (logFileName);
}

void openLog(string logFileName) {
    closeLog();
    LogFileHandle = FileOpen(logFileName, FILE_READ | FILE_WRITE | FILE_CSV, '\t');
    if (LogFileHandle < 0)
        printLastError("Can''t open log file " + logFileName);
}

void closeLog() {
    flushLog();
    if (LogFileHandle >= 0) {
        FileClose(LogFileHandle);
        printLastError("File Close " + LogFileHandle);
    }
}

void flushLog() {
    if (LogFileHandle >= 0) {
        FileFlush(LogFileHandle);
        printLastError("File Close " + LogFileHandle);
    }   
}

// prints message to system log and expert file
void log(string message) {
    Print(message);
    if (LogFileHandle >= 0) {
        int wrote = FileWrite(LogFileHandle, TimeToStr(LocalTime(), TIME_DATE | TIME_SECONDS), 
                        message);
        if (wrote < 0)
            printLastError("log " + LogFileHandle);
    }
}

//check last error and if any log it 
int logLastError(string source) {
    int err = GetLastError();
    //0 == ERR_NO_ERROR, 4000 = ERR_NO_MQLERROR
    if (err == 0 || err == 4000)
        return (0);
    
    log(source  + "-> error " + err + ": "  +       ErrorDescription(err));
    return (err);
}

bool printLastError(string source) {
    int err = GetLastError();
    //0 == ERR_NO_ERROR, 4000 = ERR_NO_MQLERROR
    if (err == 0 || err == 4000)
        return (false);
    
    Print(source + " error " + err + ": "  + ErrorDescription(err));
    return (true);
}

string StringReplace(string text, int oldChar, int newChar) {
    for (int i = 0; i < StringLen(text); i++) {
        int ch = StringGetChar(text, i);
        if (ch == oldChar)
            text = StringSetChar(text, i, newChar);
    }
    
    return (text);
}



Кто-нибудь знает как открыть файл на запись, чтобы информация добавлялась к уже существующей?

В документации по FileOpen написано: "Note:Files can be opened only from terminal_dir\experts\files directory and it's sub directories. "

В папке files файлы создаются, но как создать файл в подпапке? Пробовал "dir/file.txt" и "dir\file.txt" - не создает.

 
Кто-нибудь знает как открыть файл на запись, чтобы информация добавлялась к уже существующей?

В папке files файлы создаются, но как создать файл в подпапке? Пробовал "dir/file.txt" и "dir\file.txt" - не создает.

FileOpen ( "logs\ExpertName.txt", FILE_READ | FILE_WRITE, " " );


чтоб записывать в поддиректорию, надо создать её "ручками".

 

чтоб записывать в поддиректорию, надо создать её "ручками".

Гениально! :)
 
если будет использоваться
string t = TimeToStr(LocalTime(), TIME_DATE|TIME_SECONDS);


то имя файла будет меняться каждую секунду. Наверное, надо

string t = TimeToStr(LocalTime(), TIME_DATE);

???

 

чтоб записывать в поддиректорию, надо создать её "ручками".

Гениально! :)

да, меня этот момент тоже порадовал =)
я тоже логгер делал, вот и наткнулся..
 
если будет использоваться
string t = TimeToStr(LocalTime(), TIME_DATE|TIME_SECONDS);


то имя файла будет меняться каждую секунду. Наверное, надо

string t = TimeToStr(LocalTime(), TIME_DATE);

???



Все правильно. Лог создается в init() - поскольку нельзя в файл дописывать информацию, то при следующем запуске эксперт должен писать уже в новый файл, чтобы не потерялся предыдущий вывод. Если бы можно было дописывать, то тогда бы, конечно, в имени лога была только дата без времени.
 
Если бы можно было дописывать

FILE_READ | FILE_WRITE


я же уже писАл )

___________________
не понимаю, зачем FILE_CSV - у тебя же txt - файл..... я правда сам не знаю, что это (цсв) значит =)

 

чтоб записывать в поддиректорию, надо создать её "ручками".

Гениально! :)

да, меня этот момент тоже порадовал =)
я тоже логгер делал, вот и наткнулся..

Думаю, что надо нам сделать автоматическое создание каталогов при открытии файлов.
 
Думаю, что надо нам сделать автоматическое создание каталогов при открытии файлов.

мы именно это и имели в виду ) спасибо
 
Если бы можно было дописывать

FILE_READ | FILE_WRITE


я же уже писАл )

___________________
не понимаю, зачем FILE_CSV - у тебя же txt - файл..... я правда сам не знаю, что это (цсв) значит =)



CSV для того, чтобы время и текст сообщения разделялись табуляцией (или другим символом), что удобно при импорте лога в другую программу и просмотра только части сообщений определенного типа.

FILE_READ | FILE_WRITE пробовал - все равно не дописывает, а затирает прежнее содержимое.

Кстати, сегодня на летнее время перешли, а функция LocalTime() (точнее коммбинация TimeToStr(LocalTime(), TIME_DATE | TIME_SECONDS) - может и в TimeToStr ошибка) возвращает время на час меньше, хотя в журнале экспертов правильное локальное время показывается.
 
FILE_READ | FILE_WRITE пробовал - все равно не дописывает, а затирает прежнее содержимое.

ты забыл перенести "курсор" в конец ;)
FileSeek( LogFileHandle, 0, SEEK_END );