|
Логирование данных в файл. |
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 30)
|
Mar 20 2018, 09:43
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(Jenya7 @ Mar 20 2018, 12:02)  ... Как вообще сделать покрасивше? Через очередь - Пишете все логи в очередь сообщений, а в отдельном потоке выгребаете из нее и пишете туда куда надо и со всеми плюшками и шлю. наворотами  Удачи! Rob.
|
|
|
|
|
Mar 20 2018, 10:01
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
QUOTE (Jenya7 @ Mar 20 2018, 17:02)  1. Прежде всего проверить есть ли место на SD - вопрос как это сделать? и если нет места? очистить файл и начать писать сначала? Проверить место. Если нет, стереть самый старый файл. Попутно об этом уведомить либо через терминал, либо в отдельный файл. QUOTE (Jenya7 @ Mar 20 2018, 17:02)  2. Если файл открыт - добавить данные в файл, посмотреть флаг закрыть файл или нет.(я не хочу часто дергать файл - открывать\закрывать) Как-то так. Но аккуратно с многопоточностью. QUOTE (Jenya7 @ Mar 20 2018, 17:02)  Как вообще сделать покрасивше? Как уже сказали выше, самое правильное, писать из разных потоков в одну очередь. А в отедльной задаче выгребать из очереди сообщения, и писать их в файл. Тут уже хоть в один, хоть в несколько, т.к. только один поток заведует логом.
--------------------
Выбор.
|
|
|
|
|
Mar 20 2018, 10:12
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Если подвести итог вышесказанному получиться что то такое Код FILE *g_log_fp; int g_log_file_size;
void LOG_LogMessage(char *file, char *message, int value, int close) { int file_size = 0; char buff[256] = { '\0' }; char sval[10]; ItoA(value, sval); strcat(buff, message); strcat(buff, sval);
if (g_log_fp == NULL) { g_log_fp = fopen(file, "a+"); if (g_log_fp != NULL) fputs(buff, g_log_fp); } else fputs(buff, g_log_fp); fseek(g_log_fp, 0, SEEK_SET); fseek(g_log_fp, 0, SEEK_END); file_size = ftell(g_log_fp); if (close) fclose(g_log_fp); else fflush(g_log_fp); if (file_size >= MAX_LOG_FILE_SIZE) { //LOG_Clear() ??? //go to the next file ??? } } или я что то упустил в логике? или через очередь ? Код char log_buffer[1024]; MSG_Q_ID log_messages_Q;
void LOG_Init(void) { log_messages_Q = msgQCreate(100, 1024, 0); }
void LOG_SengQ(char *message, int value) { int size = strlen(message) + 4; //4 - for value char sval[10]; log_buffer[0] = '\0'; ItoA(value, sval); strcat(log_buffer, message); strcat(log_buffer, sval); msgQSend(log_messages_Q, log_buffer, size, NO_WAIT, MSG_PRI_NORMAL); } и потом в отдельном потоке msgQReceive(log_messages_Q, log_buffer, 1024, NO_WAIT); ? я не думаю что очередь дает какие то преимущества.
Сообщение отредактировал Jenya7 - Mar 20 2018, 10:29
|
|
|
|
|
Mar 20 2018, 10:40
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(Jenya7 @ Mar 20 2018, 11:02)  Как вообще сделать покрасивше? Я исследовал быстродействие FatFS. РезультатыКак видно время открытия и закрытия не такое уж критичное. Поэтому у меня задача лога всегда открывает и закрывает файл после каждой инспекции очереди сообщений. Задача лога имеет самый низкий приоритет. Очередь сообщений циклическая, особое внимание требует разруливание ситуаций переполнения очереди, поскольку это частая ошибка когда код начинает случайно логить в цикле. А вот операция получения объема свободного места очень затратная по времени. Так же не рекомендую создавать много мелких файлов, это увеличит время открытия и закрытия файлов. Надо также думать сколько открытых файлов может одновременно поддерживать файловая система и сколько это занимает памяти. Лучше не держать долго открытые файлы. Тогда лог будет иметь меньше влияния на остальной код который тоже может применять FS.
|
|
|
|
|
Mar 20 2018, 10:50
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(AlexandrY @ Mar 20 2018, 15:40)  Я исследовал быстродействие FatFS. РезультатыКак видно время открытия и закрытия не такое уж критичное. Поэтому у меня задача лога всегда открывает и закрывает файл после каждой инспекции очереди сообщений. Задача лога имеет самый низкий приоритет. Очередь сообщений циклическая, особое внимание требует разруливание ситуаций переполнения очереди, поскольку это частая ошибка когда код начинает случайно логить в цикле. А вот операция получения объема свободного места очень затратная по времени. Так же не рекомендую создавать много мелких файлов, это увеличит время открытия и закрытия файлов. Надо также думать сколько открытых файлов может одновременно поддерживать файловая система и сколько это занимает памяти. Лучше не держать долго открытые файлы. Тогда лог будет иметь меньше влияния на остальной код который тоже может применять FS. так все таки с очередями лучше чем первый вариант? я не вижу существенной разницы. только в первый вариант нужно добавить семафор.
Сообщение отредактировал Jenya7 - Mar 20 2018, 10:50
|
|
|
|
|
Mar 20 2018, 11:25
|
Профессионал
    
Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757

|
Цитата(Jenya7 @ Mar 20 2018, 13:12)  Код char buff[256] = { '\0' }; strcat(buff, message); strcat(buff, sval); Что, 255 байт хватит всем? Никогда не используйте функции, не контролирующие выход за границу буфера. Используйте strncat, уж если на то пошло. Или strlcat.
|
|
|
|
|
Mar 20 2018, 12:01
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(andrew_b @ Mar 20 2018, 16:25)  Что, 255 байт хватит всем? Никогда не используйте функции, не контролирующие выход за границу буфера. Используйте strncat, уж если на то пошло. Или strlcat. IAR давал мне возможность Код int size = strlen(message); char buff[size ] = { '\0' }; в vxWorks я такую возможность не нашел вот и извращаюсь. динамическую алокацию отвергаю по возможности.
Сообщение отредактировал Jenya7 - Mar 20 2018, 12:11
|
|
|
|
|
Mar 20 2018, 12:13
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Jenya7 @ Mar 20 2018, 12:02)  У меня по всему коду разбросанны сообщения типа printf ("LIB ID = %d\n", lib_id); . . . Сейчас нужно некоторые сообщения логировать в файл на SD карте. . . . Как вообще сделать покрасивше? Rem: ф-ия printf довольно "массивная" из-за своей универсальности. Соотв-но время на ее работу немалое. Вам возможно имеет смысл пересмотреть структуру вывода на терминал и логгирования с точки зрения "событийности". При возникновении события вместо "балета" с формированием строки через printf и выводом ее на USART фиксировать данные по этому событию в бинарной форме { Timestamp, CodeEventId , DataEvent }. При этом все пишется в очередь, из которой эти записи извлекаются и выводятся в лог (без переформатирования) и на терминал (через парсер-конвертер с printf) Неэффективно использовать в лог-массивах данные в не оптимальном "человеческом" формате. Их неудобно обрабатывать, они занимают больше места.
|
|
|
|
|
Mar 20 2018, 12:13
|
Профессионал
    
Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757

|
Цитата(Jenya7 @ Mar 20 2018, 15:01)  IAR давла мне возможность Код int size = strlen(message); char buff[size ] = { '\0' }; в vxWorks я такую возможность не нашел Это C99 как минимум. Цитата вот и извращаюсь. динамическую алокацию отвергаю по возможности. Вы не поняли. Если вы выделили под сообщение буфер определённого размера, то strncat не позволит выйти за границу буфера. Она просто обрежет сообщение по длине.
|
|
|
|
|
Mar 20 2018, 12:28
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Jenya7 @ Mar 20 2018, 14:14)  у меня ОС с задачами. выделить одну задачу на забор пакетов из очереди и записи в файл? Как тут уже сказали - должна быть отдельная задача, которая вычитывает данные из очереди и пишет их в файл. Но кроме того, и многозадачное добавление данных в очередь тоже должно быть потокобезопасным. Цитата(Jenya7 @ Mar 20 2018, 14:24)  какие? только не говорите sprintf  Нет. Я говорил уже не раз на форуме: stdlib IAR-а (и многих других компиляторов) имеет внутреннюю функцию: extern "C" int _Printf( void *(*)(void *, int), void *, const char *, va_list *);
Она не декларирована в IAR-овских хидерах, но все прочие декларированные вовне printf, sprintf, vsprintf и всё это семейство внутри вызывают именно её. Она обладает максимальными возможностями из всего этого семейства printf*, включает всё. Я у себя в проектах IAR использую только её. И никаких других sprintf() или чего-то ещё.
|
|
|
|
|
Mar 20 2018, 12:31
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(jcxz @ Mar 20 2018, 17:24)  Как тут уже сказали - должна быть отдельная задача, которая вычитывает данные из очереди и пишет их в файл. Но кроме того, и многозадачное добавление данных в очередь тоже должно быть потокобезопасным. а я вот туплю - как инициализировать семафор. я пользовался уже готовыми semTake, semGive. Цитата(jcxz @ Mar 20 2018, 17:28)  Нет. Я говорил уже не раз на форуме: stdlib IAR-а (и многих других компиляторов) имеет внутреннюю функцию: extern "C" int _Printf( void *(*)(void *, int), void *, const char *, va_list *); Она не декларирована в IAR-овских хидерах, но все прочие декларированные вовне printf, sprintf, vsprintf и всё это семейство внутри вызывают именно её. Она обладает максимальными возможностями из всего этого семейства printf*, включает всё. Я у себя в проектах IAR использую только её. И никаких других sprintf() или чего-то ещё. вы уж меня извините но тащить этого монстра в свой проект я не буду.
|
|
|
|
|
Mar 20 2018, 12:38
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Jenya7 @ Mar 20 2018, 14:30)  а я вот туплю - как инициализировать семафор. я пользовался уже готовыми semTake, semGive. Я не знаю как это делать в vxWork - не использовал её. Но да - потокобезопасное добавление данных в очередь можно сделать на базе семафора. Это один из вариантов. Другие варианты: а) критическая секция; б) интерфейс на базе аналога InterlockedCompareExchangePointer() + дин.память; в)...? Цитата(Jenya7 @ Mar 20 2018, 14:31)  вы уж меня извините но тащить этого монстра в свой проект я не буду.  В смысле?? А это разве не Ваше?: Цитата(Jenya7 @ Mar 20 2018, 11:02)  У меня по всему коду разбросанны сообщения типа printf ("LIB ID = %d\n", lib_id); Читайте внимательнее мои посты: Любая printf*-функция внутри вызывает _Printf() (в IAR). Воспользуйтесь отладчиком чтобы убедиться. Так что Вы затащили ещё большего "монстра" к себе
|
|
|
|
|
Mar 20 2018, 12:53
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(jcxz @ Mar 20 2018, 17:38)  Я не знаю как это делать в vxWork - не использовал её. Но да - потокобезопасное добавление данных в очередь можно сделать на базе семафора. Это один из вариантов. Другие варианты: а) критическая секция; б) интерфейс на базе аналога InterlockedCompareExchangePointer() + дин.память; в)...? В смысле?? А это разве не Ваше?: Читайте внимательнее мои посты: Любая printf*-функция внутри вызывает _Printf() (в IAR). Воспользуйтесь отладчиком чтобы убедиться. Так что Вы затащили ещё большего "монстра" к себе  нет. это - printf ("LIB ID = %d\n", lib_id); - в vxWork - там мне не важно, там у меня мощный камень и ОС. но в проектах на IAR я printf не использую.
|
|
|
|
|
Mar 20 2018, 13:02
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
QUOTE (Jenya7 @ Mar 20 2018, 18:12)  я не думаю что очередь дает какие то преимущества. Эстетические) Процессы асинхронно просто вызывают некую функцию CODE pushMsgToLog(...) , которая уже внутри помещает сообщение в очередь. Получается естественно. Другая задача асинхронно читает очередь, и получив очередное сообщение, форматирует его, готовит к записи в соответствующий файл.
--------------------
Выбор.
|
|
|
|
|
Mar 20 2018, 13:08
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(haker_fox @ Mar 20 2018, 16:02)  Эстетические) ... И не только красота - правильная очередь и функция записи в нее позволить логровать например из прерываний или из других нехороших мест куда обычному printf вход заказан. Удачи! Rob.
|
|
|
|
|
Mar 20 2018, 13:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(jcxz @ Mar 20 2018, 16:15)  Заказан кем? Достаточный размер стека и... вуаля! - sprintf прекрасно работает и из ISR.  Вобще то printf и sprintf это немного разные пчелы - жужжат по разному. И стек этот наверное прямо в мозгу программиста будет - чтобы инфу получал без IO функций. Удачи! Rob.
|
|
|
|
|
Mar 20 2018, 15:10
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(RobFPGA @ Mar 20 2018, 15:30)  Вобще то printf и sprintf это немного разные пчелы - жужжат по разному. И стек этот наверное прямо в мозгу программиста будет - чтобы инфу получал без IO функций.  Вы не поверите, но практически одинаковые! Так как внутри они почти сразу вызывают указанную мной _Printf(). Только одна в первом аргументе передаёт ей указатель на callback-функцию записи в ОЗУ, а другая - на callback-функцию записи в поток ввода/вывода. У меня, например, среди прочего _Printf() пишет прямо в поток TCP-сокета (расчленяя вывод на лету на отдельные кадры без промежуточного буфера и поддерживая ретрансмиссию тоже без буфера). Свои callback-функции для _Printf() невероятно расширяют её возможности. Всё ограничивается только фантазией программиста. А уж тривиальный вывод в буфер ограниченного размера делается через _Printf() на раз.
|
|
|
|
|
Mar 20 2018, 15:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(jcxz @ Mar 20 2018, 18:10)  Вы не поверите, но практически одинаковые! Так как внутри они почти сразу вызывают указанную мной _Printf(). Только одна в первом аргументе передаёт ей указатель на callback-функцию записи в ОЗУ, а другая - на callback-функцию записи в поток ввода/вывода. Да неужели? поверю Вам на слово Но если они для Вас так одинаковы - что мешает Вам использовать printf в прерывании? Цитата(jcxz @ Mar 20 2018, 18:10)  У меня, например, среди прочего _Printf() пишет прямо в поток TCP-сокета (расчленяя вывод на лету на отдельные кадры без промежуточного буфера и поддерживая ретрансмиссию тоже без буфера). Свои callback-функции для _Printf() невероятно расширяют её возможности. Всё ограничивается только фантазией программиста. А уж тривиальный вывод в буфер ограниченного размера делается через _Printf() на раз. То есть пока ACK для сегмента не получим из printf не уйдем ? Да уж - фантазия программиста страшная штука - но моя только заставляла меня свои _Printf() писать падла  Удачи! Rob.
|
|
|
|
|
Mar 20 2018, 15:57
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(RobFPGA @ Mar 20 2018, 17:30)  Но если они для Вас так одинаковы - что мешает Вам использовать printf в прерывании? Ничего. Если будет нужно - использую. Цитата(RobFPGA @ Mar 20 2018, 17:30)  То есть пока ACK для сегмента не получим из printf не уйдем ? Да с чего бы? Для каждого отправляемого TCP-сегмента _Printf() естественно вызывается отдельно. У меня весь сетевой стек построен построен на callback-ах: от самого низа (Ethernet-DMA) до верхних HTTP и пр. - всё в пределах одной задачи ОС. Цитата(RobFPGA @ Mar 20 2018, 17:30)  моя только заставляла меня свои _Printf() писать падла  Свой лисапед? А зачем если готовый есть? Он вроде даже позволяет добавить обработку своих дополнительных букв %...
|
|
|
|
|
Mar 20 2018, 16:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(jcxz @ Mar 20 2018, 18:57)  ... Свой лисапед? А зачем если готовый есть? Он вроде даже позволяет добавить обработку своих дополнительных букв %... Так я ж и говорю - неуемная фантазия программиста ну и ADuC812  - страшная штука! Успехов! Rob.
|
|
|
|
|
Mar 21 2018, 05:51
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(haker_fox @ Mar 21 2018, 03:43)  Опасаюсь, что sprintf может задержать прерывание на время парсинга. А так - бросил в очередь. И пусть отдельная задача неспеша всё пишет. Эт ж зависит от реализации. sprintf не боле чем имя, которое может быть переопределено. В компиляторах даже обязывают проводить адаптацию нижнего уровня функций класса printf. Так что объективно рассуждать о них под embedded не имеет смысла, там может быть что угодно. В моих проектах printf применяется в прерываниях, поскольку выводит синхронно без циклов ожидания в канал RTT, профилирован и имеет известную глубину стека. Т.е. полностью детерминирован.
|
|
|
|
|
Mar 21 2018, 08:39
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(haker_fox @ Mar 21 2018, 03:43)  Опасаюсь, что sprintf может задержать прерывание на время парсинга. Любое действие программы задерживает процессор. Это неизбежность. 0-тактовых команд в ARM пока нету. А насчёт того на сколько: так у прерываний приоритеты есть и менее приоритетные никак не должны задерживать более приоритетные. Да и голова у написателя кода тоже должна наличествовать. А так: у Cortex-M вообще есть такой режим работы, когда он только в прерываниях и работает, а выходя из прерываний сразу впадает в сон. В таком режиме никакого кода кроме кода выполняющегося в ISR просто нету.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|