Передача лога о выполняемых действиях из подчиненного уровня
От: es3000  
Дата: 22.05.19 10:24
Оценка:
Здравствуйте!

Подскажите, пожалуйста:
как правильно делается передача лога (протокола, журнала) о выполняемых действиях в подчиненных модулях на вышестоящий (вызывающий) уровень?

Есть программа обмена с кассами.
Главная форма отображает:
— таблицу касс с тремя колонками: флажок выбора кассы для выполнения операции, название кассы, результат последнего обмена;
— две кнопки: "Выгрузить" и "Загрузить".
После нажатия на кнопку и выполнения обмена (загрузки или выгрузки) в колонке "Результат" для соответствующей кассы должно быть написано типа "Успех" или "Ошибка".
Чтобы узнать подробнее, что происходило при обмене, можно щелкнуть на поле "Результат" и открывается дополнительная форма, в которой отображается более подробная информация обо всех действиях с кассой в виде списка текстовых строк типа журнала (или лога).
Пока для простоты журнал представляет собой просто массив строк.
Например:
— "В настройках кассы не указан каталог обмена"
— "Отсутствует каталог обмена"
— "Ошибка записи данных в файл obmen.txt"
— "Не выполнен обмен с кассой Касса5"

Проблема в том, что обработка обмена реализована несколькими классами, которые вызывают друг друга.
Я разбил все классы на уровни, основные уровни: UI, Бизнес-логика, Обмен с кассой в конкретном формате.
И получилась большая "глубина" вызовов.
Например:
класс "Главная форма" -> презентер -> контроллер "Обработка списка касс" — > класс бизнес-логики "Операция с кассой" -> класс "Обмен в формате ХХХ" -> Работа с файловой системой и т. д.
То есть самый "глубокий" класс ничего не знает о самом верхнем классе (о Главной форме), в который надо передать лог-журнал.

Кроме того, при работе "внутренних" классов и модулей могут возникать исключения.
Эти исключения должны перехватываться, и также записываться в этот "вышестоящий" журнал.
А также, чисто теоретически, все это может выполняться в многопоточном режиме и причем с разных рабочих мест.

Как это делается?

Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.
Но это очень не удобно.
Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.
А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.

Как лучше сделать?
Отредактировано 22.05.2019 10:25 es3000 . Предыдущая версия .
Re: Передача лога о выполняемых действиях из подчиненного уровня
От: Буравчик Россия  
Дата: 22.05.19 16:15
Оценка:
Здравствуйте, es3000, Вы писали:

E>Проблема в том, что обработка обмена реализована несколькими классами, которые вызывают друг друга.

E>Я разбил все классы на уровни, основные уровни: UI, Бизнес-логика, Обмен с кассой в конкретном формате.
E>И получилась большая "глубина" вызовов.
E>Например:
E>класс "Главная форма" -> презентер -> контроллер "Обработка списка касс" — > класс бизнес-логики "Операция с кассой" -> класс "Обмен в формате ХХХ" -> Работа с файловой системой и т. д.
E>То есть самый "глубокий" класс ничего не знает о самом верхнем классе (о Главной форме), в который надо передать лог-журнал.

Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности?
Что они принимают на вход и какой результат возвращают?

E>Кроме того, при работе "внутренних" классов и модулей могут возникать исключения.

E>Эти исключения должны перехватываться, и также записываться в этот "вышестоящий" журнал.
E>А также, чисто теоретически, все это может выполняться в многопоточном режиме и причем с разных рабочих мест.

Исключения — обрабатывать. Для многопоточного режима — создать особый, МногопоточныйЖурнал (реализация IЖурнал, см. ниже)

E>Как это делается?


"Обмен в формате ХХХ" в любом случае должен вернуть статус операции ("Успех/Отказ")

Что касается журнала, то два варианта:
Можно договориться, что при вызове "Обмен в формате ХХХ" должен возвращать журнал (список строк) наряду со статусом операции

Можно наоборот передать класс Журнала (реализация IЖурнал) в класс "Обмен в формате ХХХ" и договориться, что если понадобится куда-то что-то вывести, то он будет использовать переданный журнал. Затем сделать ФайлЖурнал, который реализовывает IЖурнал, если нужно вести журнал в файле. Или сделать ПамятьЖурнал, который реализовывает IЖурнал, если нужно вести журнал в массиве строк. А может ОблакоЖурнал, который хранит журнал в облаке.

Таким образом у тебя уйдет зависимость "Обмен в формате ХХХ" от файловой системы. С другой стороны, ты сможет работать хоть с файлами, хоть с облаком, хоть с памятью.

E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.

E>Но это очень не удобно.
E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.

Достаточно вывод в файл заменить на вывод в IЖурнал.

E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.


О классах знать не должен, а о простых интерфейсах — может.
Best regards, Буравчик
Re[2]: Передача лога о выполняемых действиях из подчиненного
От: es3000  
Дата: 23.05.19 09:06
Оценка:
Б>Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности?
Б>Что они принимают на вход и какой результат возвращают?

Главная форма:
— таблица строк с колонками "Флажок, Касса, Результат выгрузки, Результат загрузки"
— Кнопки "Выгрузить", "Загрузить"
— по событиям от кнопок вызывает методы Презентера "ЗагрузитьДанные" и "ВыгрузитьДанные"
— при щелчке на колонке "Результат" таблице вызывает метод Презентера "Подробности"
Презентер — логика интерфейса — обрабатывает события от контролов формы
— Методы "ЗагрузитьДанные" и "ВыгрузитьДанные": создают список отмеченных касс и передают этот список методам Контролера с тем же названием
— Метод "КассаОбработана", который вызывается из Контроллера обновляет поля таблицы на форме (результат) для конкретной кассы
— Метод "Подробности": получает от Контроллера последнюю операцию с кассой и открывает форму "Подробный результат"
Контроллер "Обработка списка касс"
— Входные данные: список отмеченных касс
— подписка на событие "Касса обработана" Сценария
— При срабатывании события получает кассу, ее результат и отправляет Презентеру методу "КассаОбработана"
— При запросе от Презентера возращает ему последнюю операцию с кассой
Класс БЛ "Сценарий обработки касс по списку"
— хранит обработанных список касс
— хранит для каждой кассы последнюю выполненную операцию
— Метод "ОбработатьКассы":
— в цикле для каждой кассы проверяет настройки кассы
— создает экземпляр "Операции с кассой", вызывает его метод "Выполнить"
— вызывает подписчик на событие "КассаОбработана" с передачей параметров — Касса, Операция
Класс БЛ "Операция с кассой" (базовый):
— хранит Результат (в зависимости от операции есть дополнительные реквизиты у результата)
Класс БЛ "Выгрузка в кассу" — наследник "Операция с кассой""
— реализуют конкретную операцию — выгрузка (или загрузка)
— извлекает данные из БД
— вызывает методы класса "Обмен в формате ХХХ"
— сохраняет результат ("Успех" или "Ошибка")
— устанавливает дополнительные поля результата (количество всех товаров, итоговая сумма)
Класс "Обмен в формате ХХХ":
— знает какие файлы надо читать\записывать и в каком формате
— записывает \ читает даные
— конвертирует эти данные между форматом Бизнес-логики и форматом ХХХ

Журнал должен отображаться Презентером.
В этот Журнал должны попасть все сообщения о выполняемых действиях из нижележащих классов.
Например, в классе "Обмен в формате ХХХ" может быть такое сообщение:
Журнал.Отладка("Записываю файл kassa1.txt");
Журнал.Отладка("Файл kassa1.txt записан успешно");
Перехват всех исключений будет выполнен в методе "Сценарий.ОбработатьКассы" и второй раз в методе "Презентер.КассаОбработана".

Как протащить ссылку на Журнал с самого верха до самого низа?
Отредактировано 23.05.2019 9:07 es3000 . Предыдущая версия .
Re[2]: Передача лога о выполняемых действиях из подчиненного уровня
От: es3000  
Дата: 23.05.19 09:19
Оценка:
Б>"Обмен в формате ХХХ" в любом случае должен вернуть статус операции ("Успех/Отказ")

Б>Что касается журнала, то два варианта:

Б>Можно договориться, что при вызове "Обмен в формате ХХХ" должен возвращать журнал (список строк) наряду со статусом операции

В этот журнал должен писать не только "Обмен в формате ХХХ", но и вышестоящие классы.
Так как логика конкретной операции определяется вышестоящими классами.

Б>Можно наоборот передать класс Журнала (реализация IЖурнал) в класс "Обмен в формате ХХХ" и договориться, что если понадобится куда-то что-то вывести, то он будет использовать переданный журнал.


Да, наверно лучше через интерфейс.
Тогда, получается, что этот интерфейс надо устанавливать для всех объектов, которые пишут в этот журнал.
В конструкторах у всех объектов бизнес-слоя надо передавать журнал?
Получается, весь бизнес-слой "завязан" на журнал. Это же плохо?

Б>Таким образом у тебя уйдет зависимость "Обмен в формате ХХХ" от файловой системы. С другой стороны, ты сможет работать хоть с файлами, хоть с облаком, хоть с памятью.


Зависимость от файловой системы — я имел ввиду другую.
Я имел ввиду не запись в файл журнала.
Я имел ввиду, что этот класс "знает" как работать с файловой системой (открытие\чтение\запись\закрытие файлов), чтобы записать файлы обмена с кассой.

E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.

Б>О классах знать не должен, а о простых интерфейсах — может.

То есть и сюда через конструктор передавать IЖурнал?
Но ведь модуль файловой системы работает не только с подсистемой обмена с кассами.
Одна и а же функция этого модуля, например "WriteFile()" может вызываться для обмена с кассами (и должна писать в IЖурнал).
А может вызываться и для других целей из других модулей программы — и в этом случае она также пишет в некий журнал, но эти записи не должны попасть в Журнал обработки кассы, но должны попасть например в системный журнал.
Re: Передача лога о выполняемых действиях из подчиненного уровня
От: Pzz Россия https://github.com/alexpevzner
Дата: 23.05.19 09:41
Оценка:
Здравствуйте, es3000, Вы писали:

E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.

E>Но это очень не удобно.

Зато это позволит легко собрать вместе все логи, относящиеся к конкретному запросу. И не искать их потом по всему лог-файлу. Кроме того, можно вообще не сохранять детальный лог, в случае успешного выполнения запроса. А вот в случае ошибки детали не помешают.

E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.

E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.

А ты назови этот объект как-нибудь нейтрально, например, Context. И не считай его "специальным классом вышестоящих модулей", а считай его всехним классом.
Re[2]: Передача лога о выполняемых действиях из подчиненного уровня
От: qaz77  
Дата: 23.05.19 09:56
Оценка:
Здравствуйте, Pzz, Вы писали:
Pzz>А ты назови этот объект как-нибудь нейтрально, например, Context. И не считай его "специальным классом вышестоящих модулей", а считай его всехним классом.

Даже если мы соглашаемся на такую громоздкость, как передача контекста во все методы, есть специальные случаи — конструкторы и деструкторы, из которых запись в лог очень даже может понадобиться.
Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.

Я бы для таких задач как лог сделал синглетон Environment.
В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.
Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.
Re[3]: Передача лога о выполняемых действиях из подчиненного уровня
От: Pzz Россия https://github.com/alexpevzner
Дата: 23.05.19 10:09
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Даже если мы соглашаемся на такую громоздкость, как передача контекста во все методы, есть специальные случаи — конструкторы и деструкторы, из которых запись в лог очень даже может понадобиться.


По мне, так лучше бы в пути каждого отдельного запроса не было бы конструкторов и деструкторов сколь-либо нетривиальных объектов — это плохо с точки зрения производительности. Лучше сначала сконструировать всю инфраструктуру, а потом гнать по ней запросы стройными рядами.

Q>Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.


Они могут и логи не уметь писать (или собирать их в приемломом виде). Вероятно, для таких классов уместнее было бы логировать до/после обращений к ним.

Q>Я бы для таких задач как лог сделал синглетон Environment.

Q>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.

Если в системе обрабатывается одновременно 100500 запросов, а все логи сыпятся в Environment, то потом будет трудно сводить вместе логи, относящиеся к одному запросу.

Такой синглетон было бы уместно иметь в качестве финального места, куда все логи отправляются. Пусть он думает, в какой директории их хранить, в зависимости от операционной системы и пользовательских предпочтений, как ротировать и т.п.
Re[3]: Передача лога о выполняемых действиях из подчиненного уровня
От: es3000  
Дата: 23.05.19 10:12
Оценка:
Q>Я бы для таких задач как лог сделал синглетон Environment.
Q>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.
Q>Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.

Но тогда в этот Environment.Log будут писать все и всё.
Как в Форме обмена я смогу получить из этого лога только те записи, которые имеют отношение к последнему обмену с конкретной кассой?
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
От: qaz77  
Дата: 23.05.19 10:54
Оценка:
Здравствуйте, es3000, Вы писали:
Q>>Я бы для таких задач как лог сделал синглетон Environment.
Q>>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.
Q>>Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.

E>Но тогда в этот Environment.Log будут писать все и всё.


В большинстве случаев такой подход работает.
Я же не знаю специфики твоей задачи...

E>Как в Форме обмена я смогу получить из этого лога только те записи, которые имеют отношение к последнему обмену с конкретной кассой?


Если в логи пишется id кассы, то выбрать по нему?
Или сделать раздельные логи на уровне абстракции кассы (раз уж это ее персональный лог).
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
От: qaz77  
Дата: 23.05.19 10:59
Оценка:
Здравствуйте, Pzz, Вы писали:

Q>>Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.


Pzz>Они могут и логи не уметь писать (или собирать их в приемломом виде). Вероятно, для таких классов уместнее было бы логировать до/после обращений к ним.


Не совсем понятно, как можно вклиниться до/после вызова, если это уже callback, который дергает сторонняя либа.

Например, используем сторонний XML SAX парсер.
Он дергает callback, какой-нибудь OnBeginElement(name), т.е. наш код, который что-то из xml читает.
Как нам достучаться до лога из такого callback?
Re[5]: Передача лога о выполняемых действиях из подчиненного уровня
От: Pzz Россия https://github.com/alexpevzner
Дата: 23.05.19 11:40
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Например, используем сторонний XML SAX парсер.

Q>Он дергает callback, какой-нибудь OnBeginElement(name), т.е. наш код, который что-то из xml читает.
Q>Как нам достучаться до лога из такого callback?

Там разве нельзя этому каллбеку void pointer передать в качестве контекста?

Но вообще, я не уверен, что надо каждый вызов каллбека из XML-парсера логировать. Казалось бы, достаточно залогировать сам факт, удалось ли распарсить XML, построить из него какой-то DOM, проверить его корректность, и результат этой проверки тоже залогировать. Ну еще в случае проблем можно сам сырой XML в логе сохранить, если он не необъятного размера.
Re[6]: Передача лога о выполняемых действиях из подчиненного уровня
От: qaz77  
Дата: 23.05.19 12:15
Оценка:
Здравствуйте, Pzz, Вы писали:
Pzz>Там разве нельзя этому каллбеку void pointer передать в качестве контекста?

Pzz>Но вообще, я не уверен, что надо каждый вызов каллбека из XML-парсера логировать. Казалось бы, достаточно залогировать сам факт, удалось ли распарсить XML, построить из него какой-то DOM, проверить его корректность, и результат этой проверки тоже залогировать. Ну еще в случае проблем можно сам сырой XML в логе сохранить, если он не необъятного размера.


Я же не про конкретный парсер или специфику xml...
Это только в качестве иллюстрации.

Мало ли библиотек, где в callback нет пользовательских параметров.

Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно.
Особенно, когда это такая вспомогательно-отладочная штука как лог.

Можно взглянуть на передачу контекста под другим углом.
Т.к. контекст передается во все функции, то можно сделать их методами контекста, а соответствующий параметр убрать.
Получится такой God-object, в котором сосредоточен весь зависимый от логов функционал.
В общем, дурь получается...
Re[5]: Передача лога о выполняемых действиях из подчиненного уровня
От: es3000  
Дата: 23.05.19 12:20
Оценка:
Q>>>Я бы для таких задач как лог сделал синглетон Environment.
E>>Но тогда в этот Environment.Log будут писать все и всё.

Q>В большинстве случаев такой подход работает.

Q>Я же не знаю специфики твоей задачи...

Я задачу практически уже полностью расписал.
У меня уже есть такой "глобальный" лог — он пишет все сообщения в файл.

А для операций с кассой нужен дополнительный Журнал, в котором только операции с кассой.
Re[7]: Передача лога о выполняемых действиях из подчиненного
От: es3000  
Дата: 23.05.19 12:23
Оценка:
Q>Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно.
Q>Особенно, когда это такая вспомогательно-отладочная штука как лог.

Q>В общем, дурь получается...


Точно.
Вот я и ломаю голову. Не хочется дурь делать.
Отредактировано 23.05.2019 12:24 es3000 . Предыдущая версия .
Re[3]: Передача лога о выполняемых действиях из подчиненного уровня
От: Буравчик Россия  
Дата: 23.05.19 12:58
Оценка:
Здравствуйте, es3000, Вы писали:

E>В этот журнал должен писать не только "Обмен в формате ХХХ", но и вышестоящие классы.

E>Так как логика конкретной операции определяется вышестоящими классами.

Передай и другим классам этот журнал.
Либо тот же самый экземпляр (если надо писать в этот же журнал), либо новый экземпляр (если у каждого свой журнал)

E>В конструкторах у всех объектов бизнес-слоя надо передавать журнал?


Да

E>Получается, весь бизнес-слой "завязан" на журнал. Это же плохо?

Не плохо. Лучше зависеть от абстрактного журнала, а не, например, от "журнала на файлах".

E>Зависимость от файловой системы — я имел ввиду другую.

E>Я имел ввиду не запись в файл журнала.
E>Я имел ввиду, что этот класс "знает" как работать с файловой системой (открытие\чтение\запись\закрытие файлов), чтобы записать файлы обмена с кассой.

Ну вот, теперь от файлов будут зависеть только те, кому нужны файлы, например "журнал в файле" или "обмен ХХХ с помощью файлов".

E>То есть и сюда через конструктор передавать IЖурнал?

E>Но ведь модуль файловой системы работает не только с подсистемой обмена с кассами.
E>Одна и а же функция этого модуля, например "WriteFile()" может вызываться для обмена с кассами (и должна писать в IЖурнал).
E>А может вызываться и для других целей из других модулей программы — и в этом случае она также пишет в некий журнал, но эти записи не должны попасть в Журнал обработки кассы, но должны попасть например в системный журнал.

Ты точно уверен, что WriteFile должен писать в журнал?

В первом случае передай ему MemoryJournal: IJournal, который будет писать в массив строк, которые ты позже будешь использовать в свой форме
А во втором случае SystemJournal: IJournal, который будет писать в системный журнал
Best regards, Буравчик
Re[3]: Передача лога о выполняемых действиях из подчиненного
От: Буравчик Россия  
Дата: 23.05.19 13:13
Оценка:
Здравствуйте, es3000, Вы писали:


Б>>Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности?

Б>>Что они принимают на вход и какой результат возвращают?

E>Главная форма:

E> — таблица строк с колонками "Флажок, Касса, Результат выгрузки, Результат загрузки"
E> — Кнопки "Выгрузить", "Загрузить"
E> — по событиям от кнопок вызывает методы Презентера "ЗагрузитьДанные" и "ВыгрузитьДанные"
E> — при щелчке на колонке "Результат" таблице вызывает метод Презентера "Подробности"
E>Презентер — логика интерфейса — обрабатывает события от контролов формы
E> — Методы "ЗагрузитьДанные" и "ВыгрузитьДанные": создают список отмеченных касс и передают этот список методам Контролера с тем же названием
E> — Метод "КассаОбработана", который вызывается из Контроллера обновляет поля таблицы на форме (результат) для конкретной кассы
E> — Метод "Подробности": получает от Контроллера последнюю операцию с кассой и открывает форму "Подробный результат"

Зависимость должна идти в одну сторону
Главная форма -> Презентер -> Контроллер
В обратную сторону — только сообщения/события

Поэтому контроллер не должен вызывать методы презентера
Наоборот, презентер должен понять, что операция завершена и сделать обновления формы
Понять может либо дождавшись окончания выполнения метода контроллера, либо получив сообщение от контроллера.

E>Контроллер "Обработка списка касс"

E> — Входные данные: список отмеченных касс
E> — подписка на событие "Касса обработана" Сценария
E> — При срабатывании события получает кассу, ее результат и отправляет Презентеру методу "КассаОбработана"
E> — При запросе от Презентера возращает ему последнюю операцию с кассой
E>Класс БЛ "Сценарий обработки касс по списку"
E> — хранит обработанных список касс
E> — хранит для каждой кассы последнюю выполненную операцию
E> — Метод "ОбработатьКассы":
E> — в цикле для каждой кассы проверяет настройки кассы
E> — создает экземпляр "Операции с кассой", вызывает его метод "Выполнить"
E> — вызывает подписчик на событие "КассаОбработана" с передачей параметров — Касса, Операция

Этот контроллер не делает ничего полезного, только передает сообщение следующему классу.
Думаю, стоит объединить эти два класса в один класс — АсинхроннаяОбработкаКасс
— получает на вход список касс
— выполняет заданную операцию над этими кассами
— отправляет события, что обработка кассы завершена, предоставляет результаты обработки и лог обработки

E>Класс БЛ "Операция с кассой" (базовый):

E> — хранит Результат (в зависимости от операции есть дополнительные реквизиты у результата)
E>Класс БЛ "Выгрузка в кассу" — наследник "Операция с кассой""
E> — реализуют конкретную операцию — выгрузка (или загрузка)
E> — извлекает данные из БД
E> — вызывает методы класса "Обмен в формате ХХХ"
E> — сохраняет результат ("Успех" или "Ошибка")
E> — устанавливает дополнительные поля результата (количество всех товаров, итоговая сумма)

Лучше результат операции хранить отдельно от самой операции. Т.е. создать класс для хранения результата.
Метод класса должен возвращать результат операции, а у тебя почему-то наследование от "результата операции".

E>Класс "Обмен в формате ХХХ":

E> — знает какие файлы надо читать\записывать и в каком формате
E> — записывает \ читает даные
E> — конвертирует эти данные между форматом Бизнес-логики и форматом ХХХ

E>Как протащить ссылку на Журнал с самого верха до самого низа?


Передавать в конструкторе или методе в каждом классе, который должен писать в журнал.

Либо, как я говорил выше, вообще не передавать IЖурнал, а лог возвращать как список строк внутри "результата операции кассы"
Best regards, Буравчик
Re[8]: Передача лога о выполняемых действиях из подчиненного
От: Аноним  
Дата: 23.05.19 13:19
Оценка: +1
Здравствуйте, es3000, Вы писали:
E>Вот я и ломаю голову. Не хочется дурь делать.

Если протоколирование работы касс — важная часть проекта, то надо повысить его из диагностических/отладочных средств.
Ввести как компонент бизнес-логики со всеми соответствующими взаимодействиями с DAL.

Может быть, что в результате и различные аналитические отчеты будет проще строить.
Например, если все записи лога хранить в одной таблице РСУБД, то можно будет удобно строить выборки по одной кассе, нескольким, всем...
С несколькими лог-файлами было бы сложнее и реализовывать пришлось бы врукопашную.
Re: Передача лога о выполняемых действиях из подчиненного уровня
От: kov_serg Россия  
Дата: 23.05.19 13:25
Оценка:
Здравствуйте, es3000, Вы писали:

E>Здравствуйте!


E>Подскажите, пожалуйста:

E>как правильно делается передача лога (протокола, журнала) о выполняемых действиях в подчиненных модулях на вышестоящий (вызывающий) уровень?
Очень просто передавай свой логгер который будет складывать лог для последующего отображения.

E>Как это делается?


E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.

Используй интерфейс логгера
public interface ILog {
  void Write(LogLevel level,string fmt,params object[] args);
};

И в зависимости от потребностей используй разные реализации.

E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.

Для замены не обязательно менять все методы.

E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.

???

E>Как лучше сделать?

Закажите ПО на стороне
Re[7]: Передача лога о выполняемых действиях из подчиненного уровня
От: Pzz Россия https://github.com/alexpevzner
Дата: 23.05.19 17:04
Оценка: +1
Здравствуйте, qaz77, Вы писали:

Q>Мало ли библиотек, где в callback нет пользовательских параметров.


Ну в общем-то мало, да. Потому что совершенно непонятно, как ими пользоваться, если в каллбеке невозможно понять, к чему этот каллбек относится.

Q>Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно.

Q>Особенно, когда это такая вспомогательно-отладочная штука как лог.

Q>Можно взглянуть на передачу контекста под другим углом.

Q>Т.к. контекст передается во все функции, то можно сделать их методами контекста, а соответствующий параметр убрать.
Q>Получится такой God-object, в котором сосредоточен весь зависимый от логов функционал.
Q>В общем, дурь получается...

Именно поэтому не надо так делать.
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
От: es3000  
Дата: 24.05.19 08:49
Оценка:
Б>Ты точно уверен, что WriteFile должен писать в журнал?

Не совсем так.
Класс "Работа с файловой системой" — это обертка для функций работы с файлами, используемая другими частями приложения для изоляции от конкретной библиотеки и для добавления новой функциональности (например журналирования).

Должно быть так:
class MyFileSystem
{
    IJournal mJournal;
    function WriteFile (File pFile, Data pAnyData)
    {
        try
        {
            mJournal.Info("Начинаем запись в файл.");
            openfile(pFile.filename);
            writefile{pAnyData};
            mJournal.Info("Запись в файл успешна.);
        }
        catch(...)
        {
            mJournal.Info("ошибка при записи в файл");
        }
    }
}


Только в случае обмена с кассой здесь надо сделать журналирование и в системный журнал и в журнал, имеющий отношение к конкретной кассе.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.