Войти
ФлеймФорумПрограммирование

Иона учиться программировать... логгер [C#] (4 стр)

Страницы: 1 2 3 4 5 Следующая »
#45
19:39, 13 фев. 2019

exchg
> Про эти потоки речь?
Нет, не про стандартные.
Стандартные потоки (cout, wcout, cerr, clog и т.п) thread-safe, это явно специфицировано.
Я про файловые (ну и вообще все, получается, кроме стандартных).
В коде-то

std::ofstream out("debug.txt");

#46
(Правка: 23:17) 23:14, 13 фев. 2019

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

Смотрю в хедеры

00043 namespace std _GLIBCXX_VISIBILITY(default)
00044 {
00045 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00046 
00047   /**
00048    *  @name Standard Stream Objects
00049    *
00050    *  The <iostream> header declares the eight <em>standard stream
00051    *  objects</em>.  For other declarations, see
00052    *  http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt11ch24.html
00053    *  and the @link iosfwd I/O forward declarations @endlink
00054    *
00055    *  They are required by default to cooperate with the global C
00056    *  library's @c FILE streams, and to be available during program
00057    *  startup and termination. For more information, see the HOWTO
00058    *  linked to above.
00059   */
00060   //@{
00061   extern istream cin;       /// Linked to standard input
00062   extern ostream cout;      /// Linked to standard output
00063   extern ostream cerr;      /// Linked to standard error (unbuffered)
00064   extern ostream clog;      /// Linked to standard error (buffered)
00065 
00066 #ifdef _GLIBCXX_USE_WCHAR_T
00067   extern wistream wcin;     /// Linked to standard input
00068   extern wostream wcout;    /// Linked to standard output
00069   extern wostream wcerr;    /// Linked to standard error (unbuffered)
00070   extern wostream wclog;    /// Linked to standard error (buffered)
00071 #endif
00072   //@}

std::ofstream наследуется же от ostream ? Тогда в чем смысл делать базу безопасной а ребенка нет?

#47
0:58, 14 фев. 2019

kipar
Спасибо за ценные советы,
>- зачем var stringBuilder = new StringBuilder();, если в него записывается только одна строка. Кто мешает эту же строку и передать дальше?
И в правду. Учла!

>- судя по блокировкам логгер предполагается использовать из нескольких потоков.
Скорее я хотела обезопасить его таким образом, чтобы он был thread-safe.
Но и из других потоков наверное тоже писать буду, по крайней мере планирую у себя два потока - главный и рендер, больше вроде и не зачем.

>Но тогда _curDeepLevel превратит вывод в кашу.
К сожалению да, и выглядит это так:

+ Показать

Не придумала что с этим делать...

>А отступ я бы сделал зависящим от потока который пишет.
Не представляю как это можно сделать.
Можете ли пожалуйста показать пример на основе моего кода?

+ Кслову

К слову, немного переделала лог (https://pastebin.com/qFbNMqdE), с учетом вашего замечания kipar, и с учетом подсмотренной идеи с отображением функции/файла/линии у вызывающего лог-функцию у /A\ (осталось ещё спойлер сделать... :)), ну и убрала params/formatting - проще и лаконичнее (и, может быть, быстрее?) шарповый string interpolation использовать

>- с одной стороны вроде бы все операции записи в лог блокируют тред пока запись не закончится,
Вы про LogStringToFileAsync? Эт чтобы каша в тексте (ну или в отдельно взятый на этот момент времени строке) не была (типа перваяВТОРАЯСТРОКАстрТРЕТЬЯСТРОКАока), когда в один момент текст из разных потоков пишется.

>а с другой - все равно на диск пишется раз в полсекунды.
Чтоб не насиловать дисковую подсистему на каждый чих(запись в лог) :)
Ну и чтобы каждая запись в лог не создавала микро-затыков на записи в файл. А типа "пачками" (вне зависимости - одна запись в лог была сделана за это время, или 50) скидывать их на диск. Так мне кажется эффективнее.
Или думаете это всё лишнее?

>Если важна производительность - можно ничего не блокировать, пихать записи в ConcurrentQueue
>а раз в полсекунды доставать их оттуда и писать в файл
А разве сам ConcurrentQueue внутри себя не занимается тем же самым - то есть блокирует?
Если да, то в чем тогда будет разница с моим подходом с точки зрения производительности?
Разве это оптимальнее, добавлять прослойку в виде ConcurrentQueue к уже имеющемуся у меня TextWriter'у который законекчен на класс File?
Потому как сейчас у меня получается "прямая кишка": пишу в textwriter, а он уже пишет в file.
А получится, либо textwriter убирать, либо к нему concurrentqueue добавлять.

И ещё раз - спасибо за ценные размышления/советы, прям огонь!

nerengd
>Если другие классы будут такими же огромными, то когда ты планируешь
>закончить свой движок?
Видимо, когда-нибудь :) Честно скажу, я тут пока больше кайфа от процесса пока получаю, чем от мысли о результате в виде готовой игры :)
Я ж учусь ещё пока всему этому, и мне это крайне интересно, не приелось ещё. :)
Да и, не такой уж класс логгинга у меня большой. Весьма компактный мне даже кажется, ничего лишнего :)

>Для примера мой лог:
Тоже заслуживает, наверное, право на жизнь :)

Aroch
>запись в файл хороша если не нужно следить за состоянием лога в определенный момент пока программа еще работает
>То есть такой лог будет полезен для получения фидбека от пользователей.
В этом основная цель. Ну и если крешнулось что-то, хоть иметь малейшее представление где/когда/послечего :)

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

beejah
>Алсо, Иона - это мужское имя.
И?

9K720
>Логер говно.
Ваши идеи избыточны для моих целей, на мой взгляд.
У меня, как мне кажется, всё что нужно - настраиваемо через публичные методы. Опять таки, в рамках того логгера, который я сделала, цели сделать "всея логгер" не стояло :)

#48
(Правка: 2:05) 1:54, 14 фев. 2019

Иона
> Ваши идеи избыточны для моих целей, на мой взгляд.

> В этом основная цель. Ну и если крешнулось что-то, хоть иметь малейшее
> представление где/когда/послечего :)
Ну вот посмотри в свой код и скажи, а что будет в логе если, например, закончится память и кто-то попытается об этом сообщить логеру? А если все просто упало, а таймер еще не скинул буфера? Вообще - таймер в логе зачем? А если внутри лога выстрелит эксепшон/не отработает одна из функций? Ну например ты не сможешь создать директорию потому что нету прав.

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

#49
6:23, 14 фев. 2019

Иона
> В идеале хотелось бы заниматься программированием графики по итогу
Может тогда с этого стоит начать ?

#50
10:02, 14 фев. 2019

exchg
> Ну вот посмотри в свой код и скажи, а что будет в логе если, например,
> закончится память и кто-то попытается об этом сообщить логеру? А если все
> просто упало, а таймер еще не скинул буфера?
+1. Если с помощью лога отлаживать падения, то очень важно чтобы на момент падения последние строки в файле соответствовали последним вызовам логгера. Как минимум, при эксепшене точно стоит делать flush. Падения без эксепшена, наверное, для шарпа не так актуальны как для нативных языков, но я всегда не заморачивался и просто делал flush на каждой строчке.

Иона
> Ну и чтобы каждая запись в лог не создавала микро-затыков на записи в файл. А
> типа "пачками" (вне зависимости - одна запись в лог была сделана за это время,
> или 50) скидывать их на диск. Так мне кажется эффективнее.
> Или думаете это всё лишнее?
Ну и вторая сторона - если лог пишет по 100 сообщений в секунду, то
- такой объем текста будет сложно читать.
- он будет быстро забивать диск.
И это при том что 100 flushей в секунду еще не будут тормозить.

> Не представляю как это можно сделать.
> Можете ли пожалуйста показать пример на основе моего кода?
var _curDeepLevel = new Dictionary<ThreadID, int>();
и соответсвенно каждый поток будет инкрементировать свой уровень вложенности. Я обычно все равно имя потока в сообщениях логгера вывожу, но наверное это не всем надо.

> А разве сам ConcurrentQueue внутри себя не занимается тем же самым - то есть
> блокирует?
> Если да, то в чем тогда будет разница с моим подходом с точки зрения
> производительности?
пишут https://habr.com/ru/post/245837/ что нет, не блокирует. Сам конечно не проверял.

#51
14:25, 14 фев. 2019

exchg
> По логике что файловый, что стандартный стрим должны иметь одну реализацию, по
> крайней мере в идеале.
По логике, выше - бессмысленное утверждение. "файловый" и "стандартный" - это ортогональные характеристики. У тебя стандартный поток может быть файловым, может быть перенаправлен в файловый, может гнать в консоль, может куда угодно гнать. Стандартный поток - он абстрактный.

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

> std::ofstream наследуется же от ostream ?
В строгом терминологическом смысле - не уверен, но я бы сказал - да.

> Тогда в чем смысл делать базу безопасной а ребенка нет?
Ух, крестушки-крестуханчики. База может (и во вселенной нормального человека должна, лол) быть абстрактной, т.е не предоставлять никакой функционал вообще. Или предоставлять в виде абстрактных взаимоисключающих возможностей для последующей их настройки потомком. Да в чем угодно смысл может быть, я, шталь, СТЛ проектировал.

#52
15:41, 14 фев. 2019

Иона
> Собственно, сами файлики:
Сразу вижу следующие проблемы:
1) не пиши лог в html, слишком много ненужной и дублирующей информации. Пиши лог в xml + xslt шаблон к нему, который при открытии xml будет формировать html разметку. Кроме того из XML удобно делать выборки через XPath, а выборки при анализе логов 100% будут нужны. Хорошей практикой было бы даже XML лог делать максимально кратким:

<I t="79847343" s="Core">Initialization completed.</I>
Минимум информации, теги сокращены до одно-двухбуквенных, время в виде timestampt. При просмотре через xslt приводить в нормальный вид.

2) у тебя логгер слишком много знает. Он вообще должен быть в виде отдельной ни от чего не зависящей компоненты. Сейчас у тебя логгер знает какие модули есть в движке и соответственно по иерархии вообще на самом верху выходит. Т.е. добавили модуль -> правим логгер.
Как у нас:
а) есть интерфейс ILogger, который реализует набор простых функций, типа: LogMessage(string source, string message, LogEntrySeverity severity...)
б) где-то есть реализация этого интерфейса - это может быть твой класс или обёртка над log4net например, это не важно.
в) есть модуль, который обычно что-то типа Application, который знает какой класс у нас в приложении реализует интерфейс ILogger, он создаёт экземпляр этого класса и кладёт его в глобальный DependencyContainer: DependencyContainer.AddInstance<ILogger>(new MyLogger())
г) в каждом модуле, который использует логгер есть свой статический внутренний класс Log, который предоставляет статические методы для логирования событий для текущего модуля, при этом для логгирования используется экземпляр класса, реализующий ILogger, который мы получаем из контейнера.

internal static class Log
{
    private const string ThisModuleName = "Core";

    private static ILogger _logger;

    static Log()
    {
        _logger = DependencyContainer.Resolve<ILogger>();
    }

    public static void LogInfo(string message)
    {
       _logger.LogMessage(ThisModuleName, message, LogEntrySeverity.Info);
    }
}
Теперь в рамках модуля использовать логгер очень просто: Log.LogInfo(....), при этом во всех модулях вызовы логгера идентичны, а сам логгер ничего не знает об архитектуре приложения.

#53
15:46, 14 фев. 2019

beejah
> По логике, выше - бессмысленное утверждение
Предположение.

> Потоки, к гадалке не ходи - не stateless.
> База может (и во вселенной нормального человека должна, лол) быть абстрактной,
> т.е не предоставлять никакой функционал вообще.
Может. А может и не быть. Вопрос был о том, что если ты все равно используешь потокобезопасные файлстримы сишки под капотом кого хрена ты выделываешся уровнем выше? Т.е. у тебя получается потоко-небезопасная херня надстроенная над потоко-безопасными механизмами? То, что я не знаю как реально устроены стримы в с++ я уже понял.

#54
(Правка: 16:14) 16:07, 14 фев. 2019

exchg
> Вопрос был о том, что если ты все равно используешь потокобезопасные файлстримы
> сишки под капотом кого хрена ты выделываешся уровнем выше?
Лол. Ты думаешь, почему стандартные C++ потоки безопасны?
Потому что стандартные С потоки безопасны.

С файловыми стримами в C - там то же самое. Один в один.
"Посикс гарантирует, стандарт не гарантирует, вот вам fwrite_nolock, чтобы мютексами не щелкать, а вообще не выеживайтесь, на хрена вам вообще асинхронно в поток писать? Ну ладно, вот вам на всякий случай еще и fdup, раз вы дураки".

> То, что я не знаю как реально устроены стримы в с++ я уже понял.
Как они устроены, нам похер. Нет задачи "исследовать все реализации СТЛ".
Есть задача "не вляпаться в вендор-специфику СТЛ".

#55
16:28, 14 фев. 2019

Я, кстати, вот так вот и с ходу придумать сценарий, в котором нам нужна была бы атомарная запись именно в абстрактный в общем (и в файловый в частности) поток, не могу. Со стандартными потоками все понятно - они наружу торчат, интегрируются черт знает куда и как, сами триды хер знает, что из себя представляют (в Ц стандарте они если и появились (я дальше C99 даже и не смотрел, лол), то уже по остаточному принципу, всем похер), там сам бог велел.

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

#56
17:57, 14 фев. 2019

beejah
> Лол. Ты думаешь, почему стандартные C++ потоки безопасны?
> Потому что стандартные С потоки безопасны.
> С файловыми стримами в C - там то же самое. Один в один.
Все ссылаются на C.11 §7.21.2

Each stream has an associated lock that is used to prevent data races when multiple threads of execution access a stream, and to restrict the interleaving of stream operations performed by multiple threads. Only one thread may hold this lock at a time. The lock is reentrant: a single thread may hold the lock multiple times at a given time.

> "Посикс гарантирует, стандарт не гарантирует, вот вам fwrite_nolock, чтобы
> мютексами не щелкать, а вообще не выеживайтесь, на хрена вам вообще асинхронно
> в поток писать?
Ну ладна там, есть же aio.

> А в файловом потоке - там по любому либо лок вообще не нужен, либо он будет
> болтаться выше, в прикладном коде. Кому на хер нужно вслепую, не синхронизируя
> свой функционал, тупо писать данные в файл с разных потоков в произвольном
> порядке?
Вот это сложный вопрос. Навскидку любой чанковый формат. Ну допустим тебе может быть все-равно в каком порядке хранятся дети у ноды. Но зачем такое может понадобиться и в чем проблема в таком (редком?) случае лочить руками - вопрос.

#57
18:53, 14 фев. 2019

exchg
> Навскидку любой чанковый формат.
Что-то я очень сильно сомневаюсь в практичности подобного именно на записи.
Если настолько сильно прижало, то, скорее всего, неконтроллируемый сброс в файло нас не устроит. Либо потоки вообще лесом пойдут, подтянется маппинг или что-то вроде этого, либо будет свой буффер, т.е синхронизация потока будет уже не нужна.

> Но зачем такое может понадобиться и в чем проблема в таком (редком?) случае
> лочить руками - вопрос.
То, что в таком случае понадобиться синхронизировать дохрена - вот без малого единица вероятность.

#58
(Правка: 19:05) 18:58, 14 фев. 2019

exchg
> Все ссылаются на C.11 §7.21.2
Что-то я не нашел там этого.
Зашибись. А вбросим-ка мы что-нибудь про thread-safety потоков. В стандарт 2011 года. В 2018 году.
"Дорогой, на пятом году женитьбы я, наконец, вспомнила, что хотела тебе сказать. У меня ВИЧ."
Ну, у меня нету свежего, я не могу проверить.

#59
19:38, 14 фев. 2019

beejah
> Зашибись. А вбросим-ка мы что-нибудь про thread-safety потоков. В стандарт 2011
> года. В 2018 году.
тут еще не было - Committee Draft — December 2, 2010ISO/IEC 9899:201x
тут уже было - Committee Draft — April 12, 2011ISO/IEC 9899:201x
в 18 были только уточнения и исправления насколько я помню.

Страницы: 1 2 3 4 5 Следующая »
ФлеймФорумПрограммирование