В большинстве случаев логирование нужно только в процессе отладки, и из конечного кода оно должно убираться (обычно комментированием), поэтому сделаем так, чтобы лишнего кода было как можно меньше. Самый минимум - одна ссылка на файл с функциями логирования и по одной строке на каждый вывод лога, набрал Log("привет"), - получил привет.
Главная задача - вывести строку в комментарий и, если комментарий слишком большой (много строк), сдвинуть его вверх. Так как хочется максимально простой для использования код, то максимальную высоту будем вычислять автоматически.
// определить максимальное количество срок (2/3 экрана) int chartHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS) - 20; // 20 - примерный размер заголовка int lineHeight = 11; // вроде бы фиксированное для комментария int lineCount = chartHeight * 2 / 3 / lineHeight; if (lineCount < 1) lineCount = 1;
Почему 2/3 экрана? Это значение хорошо выглядит, не нравится - можно изменить на другое. Сверху окна есть заголовок с именем инструмента, его надо исключить из расчётов, он занимает примерно 20 пикселей. Функция быстрой торговли может добавлять ещё очень большую плашку, но её я здесь игнорирую, в отладке мне эта штука пока не нужна была, да и запаса трети экрана обычно хватает, чтобы всё влезало и с ней.
Дальше всё просто: берём текущий комментарий, разбиваем на строки, убираем лишние сверху, если их слишком много, добавляем свою, выводим на экран.
string comment = ChartGetString(0, CHART_COMMENT); string lines[]; StringSplit(comment, '\n', lines); ArrayRemove(lines, 0, ArraySize(lines) - lineCount + 1); ArrayAdd(lines, "[" + TimeToString(TimeLocal(), TIME_MINUTES | TIME_SECONDS) + "] " + (string)line, false, lineCount); Comment(ArrayToString(lines, "\n"));
ArrayAdd, ArrayRemove, ArrayToString взяты из той же mql.xlib (util\array.mqh).
Теперь возьмёмся за входные параметры. Обычно с Print("привет ещё раз") я не заморачиваюсь приведением типа параметра к строке, делаю просто Print(value), функция делает эта сама. Сделаем и мы.
template <typename T>
void Log(const T line) {}
Поэтому выше в ArrayAdd есть приведение типа (string)line.
Всё теперь работает, супер. Не хватает одной хорошей особенности принта - возможность принимать кучу параметров и складывать их в одну строку на выходе. Можно, конечно, просто ставить плюсики вместо запятых, но реализация запятых поможет быстро перевести принты в логи.
Кстати, все эти заморочки с логом в комментариях нужны лишь тем, кому не нравятся принты. Либо в тех случаях, когда информация в лог поступает с нескольких окон, что при отладке бывает часто (мой случай).
64 параметра, как у Print, сделать не получится, только 8. Если 8 мало, конкатенация строк вам в помощь (те самые плюсики). Это ограничение на количество typename в template. Каждому параметру нужен свой тип, иначе при смешанных типах входных параметров при одном лишь <typename T> в объявлении Log() компилятор будет ругаться на неявное приведение типов.
Вот перегрузка для двух переменных, остальные 6 (c добавлением T3, T4, и так до T8) делаем аналогично.
template <typename T1, typename T2> void Log(const T1 part1, const T2 part2) { Log((string)part1 + (string)part2); }
На этом всё, можно пользоваться. Полный код файла ниже.
#include <fxcoder\xlib-v1\util\array.mqh> template <typename T> void Log(const T line) { // определить максимальное количество срок (2/3 экрана) int chartHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS) - 20; // 20 - примерный размер заголовка int lineHeight = 11; // вроде бы фиксированное для комментария int lineCount = chartHeight * 2 / 3 / lineHeight; if (lineCount < 1) lineCount = 1; string comment = ChartGetString(0, CHART_COMMENT); string lines[]; StringSplit(comment, '\n', lines); ArrayRemove(lines, 0, ArraySize(lines) - lineCount + 1); ArrayAdd(lines, "[" + TimeToString(TimeLocal(), TIME_MINUTES | TIME_SECONDS) + "] " + (string)line, false, lineCount); Comment(ArrayToString(lines, "\n")); } template <typename T1, typename T2> void Log(const T1 part1, const T2 part2) { Log((string)part1 + (string)part2); } template <typename T1, typename T2, typename T3> void Log(const T1 part1, const T2 part2, const T3 part3) { Log((string)part1 + (string)part2 + (string)part3); } template <typename T1, typename T2, typename T3, typename T4> void Log(const T1 part1, const T2 part2, const T3 part3, const T4 part4) { Log((string)part1 + (string)part2 + (string)part3 + (string)part4); } template <typename T1, typename T2, typename T3, typename T4, typename T5> void Log(const T1 part1, const T2 part2, const T3 part3, const T4 part4, const T5 part5) { Log((string)part1 + (string)part2 + (string)part3 + (string)part4 + (string)part5); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> void Log(const T1 part1, const T2 part2, const T3 part3, const T4 part4, const T5 part5, const T6 part6) { Log((string)part1 + (string)part2 + (string)part3 + (string)part4 + (string)part5 + (string)part6); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> void Log(const T1 part1, const T2 part2, const T3 part3, const T4 part4, const T5 part5, const T6 part6, const T7 part7) { Log((string)part1 + (string)part2 + (string)part3 + (string)part4 + (string)part5 + (string)part6 + (string)part7); } template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> void Log(const T1 part1, const T2 part2, const T3 part3, const T4 part4, const T5 part5, const T6 part6, const T7 part7, const T8 part8) { Log((string)part1 + (string)part2 + (string)part3 + (string)part4 + (string)part5 + (string)part6 + (string)part7 + (string)part8); }
Некоторым дальнейшим улучшениям мешают ограничения MQL, другим - нежелание всё слишком раздувать.
Комментариев нет:
Отправить комментарий