Некорректная запись в файл
От: _vanger_  
Дата: 20.06.11 20:28
Оценка:
Здравствуйте.

Есть программа, работающая круглосуточно, периодически производящая некоторые вычисления, пишущая о своих успехах в текстовый файл. Эта запись реализована примитивным логгером, представляющем собой класс, содержащий функцию записи очередного сообщения в текущий файл лога(который меняется по прошествии определённого времени). Наблюдается странный плохо воспроизводимый глюк: при длительной работе в файле лога отсутствуют некоторые строки. Причём одни и те же. Т.е. должно быть
aaa1
bbb1
ccc1
---
aaa2
bbb2
ccc2
...

а есть
aaa1
ccc1
---
aaa2
ccc2
...


Вот функция записи
void Logger::write( const char *format, ... )
{
        static bool newFile = true;
    static bool firstTime = true;

        if( timer.timePassed( period ) || firstTime )
    {
        newFile = true;

        if( !oldLogName.empty() )
            remove( oldLogName.c_str() );
        oldLogName = curLogName;
        curLogName = timer.getTimeStr();
        curLogName += ".txt";
        timer.noteDownTime();

        firstTime = false;
    }

    if( FILE *file = fopen( curLogName.c_str(), newFile ? "w" : "a" ) )
    {
        newFile = false;

        va_list args;
        va_start( args, format );
        vfprintf( file, format, args );
        va_end( args );

        fclose( file );
    }
}


Не подскажете, с чем может быть связано такой поведение?
Re: Некорректная запись в файл
От: _Dreamer Россия  
Дата: 21.06.11 04:05
Оценка: +1
Здравствуйте, _vanger_, Вы писали:

__>Здравствуйте.


__>Есть программа, работающая круглосуточно, периодически производящая некоторые вычисления, пишущая о своих успехах в текстовый файл. Эта запись реализована примитивным логгером, представляющем собой класс, содержащий функцию записи очередного сообщения в текущий файл лога(который меняется по прошествии определённого времени). Наблюдается странный плохо воспроизводимый глюк: при длительной работе в файле лога отсутствуют некоторые строки. Причём одни и те же. Т.е. должно быть

__>Не подскажете, с чем может быть связано такой поведение?

судя по коду, как минимум 2 варианта : либо fopen, либо vfprintf не отрабатывают успешно.
анализируйте коды ошибок и возвращаемое значение из vfprintf, в случае ошибки выводите в DebugOutputString, или куда-то еще.
а многопоточности у Вас там нет?
Re[2]: Некорректная запись в файл
От: _vanger_  
Дата: 21.06.11 12:41
Оценка:
Здравствуйте, _Dreamer, Вы писали:

_D>судя по коду, как минимум 2 варианта : либо fopen, либо vfprintf не отрабатывают успешно.

_D>анализируйте коды ошибок и возвращаемое значение из vfprintf, в случае ошибки выводите в DebugOutputString, или куда-то еще.
_D>а многопоточности у Вас там нет?

Не отрабатывает только fopen. vfprintf и fclose завершаются успешно.
Программа однопоточная.
Были мысли, что дело в слишком частых вызовах fopen/fclose, но следующий код работает нормально:

int main()
{
    bool first = true;
    for( int i = 0 ; ; ++i )
    {
        if( FILE *file = fopen( "zzz.txt", first ? "w" : "a" ) )
        {
            first = false;

            if( fprintf( file, "%d\n", i ) < 0 )
                printf( "failed to write\n" );

            if( 0 != fclose( file ) )
                printf( "failed to close\n" );
        }
        else
        {
            printf( "failed to open\n" );
        }
    }

    return 0;
}
Re[2]: Некорректная запись в файл
От: _vanger_  
Дата: 22.06.11 00:39
Оценка:
Проверил на другом компиляторе под другой операционкой(Debian) — то же. Т.е. это особенность именно кода, а не поведения ОС при работе с файлами или реализации стандартной библиотеки. Но, где же, чёрт возьми, собака зарыта?

Единственный экземпляр логгера объявляется без изысков в logger.h:
static Logger logger();

а logger.h через stdafx.h цепляется к остальным заголовочным файлам.
Единственное обращение к логгеру — это вызов функции write, описанной выше.
Re[3]: Некорректная запись в файл
От: _Dreamer Россия  
Дата: 22.06.11 05:44
Оценка:
Здравствуйте, _vanger_, Вы писали:

__>Не отрабатывает только fopen. vfprintf и fclose завершаются успешно.

__>Программа однопоточная.
__>Были мысли, что дело в слишком частых вызовах fopen/fclose, но следующий код работает нормально:

а что с кодами ошибок при неудочной fopen?
как говорит нам MSDN,
See _doserrno, errno, _sys_errlist, and _sys_nerr for more information on these, and other, error codes.


ну или, если не Винда, то просто errno хотя бы.
Re: Некорректная запись в файл
От: AleksandrN Россия  
Дата: 22.06.11 06:14
Оценка:
Здравствуйте, _vanger_, Вы писали:

__>Вот функция записи

__>
__>        if( timer.timePassed( period ) || firstTime )
__>    {
__>        newFile = true;

__>        if( !oldLogName.empty() )
__>            remove( oldLogName.c_str() );
__>        oldLogName = curLogName;
__>        curLogName = timer.getTimeStr();
__>        curLogName += ".txt";
__>        timer.noteDownTime();

__>        firstTime = false;
__>    }
__>}
__>


А зачем удаляется старый файл? Есть какой-то внешний процесс, который его архивирует? Если есть, то возможно, на время архивирования файл блокируется и поэтому его нельзя открыть.
Re[2]: Некорректная запись в файл
От: _vanger_  
Дата: 22.06.11 07:30
Оценка:
Здравствуйте, AleksandrN, Вы писали:

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


Просто чтобы лог бесконечно не разрастался. Внешнего процесса, работающего с файлом нет.
Re[4]: Некорректная запись в файл
От: _vanger_  
Дата: 22.06.11 10:41
Оценка:
Здравствуйте, _Dreamer, Вы писали:

_D>а что с кодами ошибок при неудочной fopen?


errno=EINVAL: Invalid argument.

Я разобрался. Дело было не в записи, а в непонимании межмодульного взаимодействия.
Прошлая реализация:
Единственный экземпляр логгера объявляется без изысков в logger.h:

static Logger logger();

а logger.h через stdafx.h цепляется к остальным заголовочным файлам.
приводила к тому, что для каждого объектного файла создавался свой экземпляр логгера. А слово static предотвращало конфликт имён, устанавливая внутреннее связывание.
string curLogName у лишних логгеров устанавливалась в "" конструктором по умолчанию. Код внутри
if( timer.timePassed( period ) || firstTime )
не выполнялся, т.к. firstTime — статическая и была уже изменена первым экземпляром логгера.

Сейчас сделал так:
в logger.cpp создаю экземпляр логгера, а в stdafx.h добавил
extern Logger logger;
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.