Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];

Вниз

Как правильно вести log файл программы???   Найти похожие ветки 

 
INTAARI   (2004-01-12 10:47) [0]

Здравствуйте господа!!!
Наверно Вы скажете кому как удобно, тот так и ведет. Меня же интересует Ваше мнение исходя из Вашего опыта по использованию log файла. Напримет, какой размер файла, сколько строк, как часто писать, переименовывать файл при большом объеме или же сдвигать строки. В моем случае этот файл необходим так как персонала нет и только по logу можно востановить картину происходивших событий (когда перестали поступать данные с датчиков, или начали приходить неверные данные). Заранее спасибо.


 
NikeOLD   (2004-01-12 12:09) [1]

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

INTAARI, лог действительно должен быть такой, чтобы было удобно и максимально информативно. Переименовывать и сколько строк - на твое усмотрение. У меня, например, создается лог при каждом запуске программы уникальный.


 
Anatoly Podgoretsky   (2004-01-12 12:16) [2]

А как тебе удобно и как ты хочешь?
И может ли быть лог типизированым фвйлом с временными отметками?


 
NikeOLD   (2004-01-12 12:58) [3]

Лог типизированным быть не может. Смотреть будет неудобно.

А хотелось бы по необходимости (например, лог превысил установленные 500 КБ) затирать самые первые записи. Не могу придумать рациональную реализацию.


 
Kerk   (2004-01-12 13:01) [4]


> NikeOLD (12.01.04 12:58) [3]

Так напиши утилитку, что бы лог смотреть. Долго что ли? В типизированном логе поиск будет легко производить..


 
Anatoly Podgoretsky   (2004-01-12 13:03) [5]

NikeOLD (12.01.04 12:58) [3]
Что то я не использую особых неудобств при использовании Event Viewer, три независимых лога, фильтрация, возможно просмотра логов на других машинах домена, работа по низкоскоростной сети и т.д.


 
INTAARI   (2004-01-12 13:11) [6]


> NikeOLD (12.01.04 12:58) [3]
> А хотелось бы по необходимости (например, лог превысил установленные
> 500 КБ) затирать самые первые записи. Не могу придумать
> рациональную реализацию

Затирание информации на мой взгляд не является правильным методом для ведения лога. Получается что мы сами затираем ту информацию которая нам нужна? Как то это не правильно. Если тебе нужен такой вариант могу скинуть, пиши.


 
NikeOLD   (2004-01-12 13:19) [7]

INTAARI, если не трудно, скинь на мыло или сюда.

А на твой вопрос скажу, что по истечении определенного промежутка времени иногда уже не важно, что там происходило.


 
yurchello   (2004-01-12 13:48) [8]

Я делал так:
1 для себя установил определённый формат логфайла (по полям - дата, источник, событие....)
2. Написал класс TLogWriter где собрал все процедуры и переменные (файлы, директории), он писал лог, перебирал их и анализировал.

и использовал этот класс во всех программах где мне нада вести лог.


 
NikeOLD   (2004-01-12 14:01) [9]


> yurchello (12.01.04 13:48) [8]

А урезать-то как. Меня это больше всего интересует. Все остальное - 15 минут работы.


 
vlv   (2004-01-12 14:04) [10]

Еще один вариант, как избежать разрастания лога -
лог-файл имеет имя - Blabla_2004-01-15.log.

Процедура записи строки в лог создает новый фыйл при смене суток.
А в строку достаточно выводить только время(без даты).
Устаревшие файлы можно убить, сархивировать и т.д.


 
Erik   (2004-01-12 15:34) [11]

Я тоже так сразу нескажу как быстро урезать лог. Тут надо блоками чтото делать.


 
John Kayfolom   (2004-01-12 17:03) [12]

Var F : File of String[255]; //Типизированный файл
begin
AssignFile(F,"Путь к файлу");
Reset(F,1); // Открываем
Seek(F,100); // перемещаем на 100 строку
Write(F,LogString); // Пишем
Seek(F,500); // перемещаем на 500 строку
Truncate(F); // обрезаем с 500 по конец файла.
Вот примерно так.


 
John Kayfolom   (2004-01-12 17:12) [13]

Мда, что то я перемудрил ;) Не все так гладко как хотелось :(


 
div123   (2004-01-12 17:40) [14]

Мне кажется для этого просто надо подгружать лог файл как типизированный БАЙТ до #13#10, после определения позиции удалять предыдущие записи
Или воспользоваться TStringList загружая его из файла и удаляя первые строки.
Все равно в любом случае весь файл надо будет переписывать


 
Anatoly Podgoretsky   (2004-01-12 17:43) [15]

Типизированый файл не обязательно удалять или перемещать позиции, он вполне может быть кольцевым с фиксированой длиной.


 
alex_***   (2004-01-12 17:44) [16]

to [15] а как файл можно закольцевать?


 
div123   (2004-01-12 17:53) [17]

Да тоже интересно [15]


 
Anatoly Podgoretsky   (2004-01-12 17:58) [18]

if N > Maxindex then N := StartIndex
...


 
alex_***   (2004-01-12 18:01) [19]

N - позиция в файле?


 
div123   (2004-01-12 18:24) [20]

Это для действительно типизированного файла, а речь как я понял идет о прямом текстовом

Хотя можно найти компромис


TZap = record
text: ShortString;
end;


Должен работать как типизированный файл с размером записи 255 byte и виден будет как обычный текстовик, только длина строки ограничена.


 
artem100   (2004-01-12 23:23) [21]

>Как правильно вести log файл программы?
дялеко не праздный вопрос
исходные данные:
Как можно точней разобраться в прошедшей ситуации.
1.Когда происходило? 2.Что происходило?
Решение:
1.писать лог как можно точней в самом совместимом формате
ASCII английская половина в TXT
Delphi реализация:
//----------------------------------------------
function WriteLog(S:string):string;//artem2001
var sTimes:string;
begin
sTimes:=DateTimeToStr(Now); //время
if FileExists(sLogFile)then begin
AssignFile(Flog,sLogFile); //дополнять протокол
// {$I-} //отключить обработку ошибок I/O
Append(Flog); //дополнять
// {$I+} //включить обработку ошибок I/O
Writeln(Flog,sTimes+" "+S);//записать строку в файл
CloseFile(Flog); //отпустить файл
end;
Result:=sTimes;
end;
//----------------------------------------
Резултат работы (Реально работающего автомата)
11.01.2004 23:17:28 EMailAttachFile start
11.01.2004 23:17:29 TimerSMTP1
11.01.2004 23:17:29 TimerPOP31
11.01.2004 23:17:29 BatFile2
11.01.2004 23:17:29 BatFile1
11.01.2004 23:17:30 || del |C:\EMAIL\POP3SMTP47\In\Temp1.mme


 
Anatoly Podgoretsky   (2004-01-12 23:36) [22]

alex_*** © (12.01.04 18:01) [19]
N индекс записи, оно же позиция в файле. Доходя до конца переходим на начало, типичный кольцевой буфер. Это позволяет очень быстро работать с логом. Поскольку размер постоянный и ничего перемещать не надо. Если задача позволяет такое решение, то очень быстро и удобно. А наличие типа озволяет гибко работать с данными.


 
Tano   (2004-01-13 07:46) [23]

Может быть красиво - ограничение по длине. Однако, шевеление лога большого размера занимает определенное время...
Можно вырезать начальную строку так:
1) выяснить длину первой строки (L), добавить #13#10 (LS)
2) выяснить текущий размер файла (FS)
3) завести в памяти буффер размера (BS=FS-LS)
4) открыть файл как безтиповый и с позиции LS (то есть сразу после 1 строки) считать все в буффер.
5) встать в 0 позицию файла и записать все из буффера.
6) встать в позицию FS-LS и отбросить содержимое файла начиная с этой позиции (Truncate вроде).
-----------
код даже не писал. Мне это кажеться геморройным. Если в проге нет объема сообщений подобного Window Messages, то вполне достаточно каждые новые сутки заводить новый файл. Удобство:
1) ведение лога становиться тривиальным (разве что дату надо периодически проверять, если прога может работать на границе суток)
2) достаточно указывать в логе только время (при анализе меньше рябить в глазах будет)
3) лишний файл n-дневной давности крайне просто грхнуть/архивнуть.


 
sniknik   (2004-01-13 08:42) [24]


unit LogsUnit;

interface

uses
Windows, SysUtils, Classes;

procedure InitEvent(Lines: TStrings);
procedure EventToLog(Msg: string; mShow: Boolean);

implementation

uses ParamUnit;

const
FileLogSize = 512; //килибайт
MemoLogSize = 2000; //строк

var
FLogFile, FLogTmp: string;
FLines: TStrings;
Buf: array[1..2048] of Char;

procedure InitEvent(Lines: TStrings);
begin
FLines:= Lines;
FLogFile:= FileLog;
FLogTmp:= ChangeFileExt(FileLog,".$$$");
end;

procedure CutLog;
var
Size, i: integer;
FromF, ToF: file;
NumRead, NumWritten: Integer;
begin
AssignFile(FromF, FLogFile);
Reset(FromF, 1);
try
size:= FileSize(FromF);
if size div 1024 > FileLogSize then begin
try
Seek(FromF, size div 5); //20% обрезание
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
i:= 1;
while (Buf[i] <> #10) and (i < 2047) do i:= i + 1;
if Buf[i] = #10 then Seek(FromF, size div 5 + i);

AssignFile(ToF, FLogTmp);
Rewrite(ToF, 1);
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
finally
CloseFile(ToF);
end;
end;
finally
CloseFile(FromF);
end;
if FileExists(FLogTmp) then begin
DeleteFile(FLogFile);
RenameFile(FLogTmp, FLogFile);
end;
end;

procedure EventToLog(Msg: string; mShow: Boolean);
var Ch: PChar;
Size, i: integer;
F: TextFile;
isExists: boolean;
begin
try
if mShow and (FLines <> nil) then begin
if FLines.Count > MemoLogSize then begin
FLines.BeginUpdate;
Ch:= FLines.GetText;
Size:= Length(Ch);
i:= Size div 5;
while (Ch[i] <> #10) and (i < Size) do i:= i + 1;
if Ch[i] = #10 then FLines.SetText(PChar(Copy(Ch, i+2, Size)));
FLines.EndUpdate;
end;
FLines.Add(Msg);
end;
isExists:= FileExists(FLogFile);
if isExists then CutLog;
AssignFile(F, FLogFile);
if isExists then Append(F)
else Rewrite(F);
WriteLn(F, Msg);
Flush(F);
CloseFile(F);
except {NOTHING} end;
end;

end.


 
panov   (2004-01-13 09:55) [25]

У меня в инфе ссылка на сайт, где лежит исходник DLL, в котором реализован класс для ведения лога в отдельном потоке.
На слабеньком компе выдерживает до 2000 записей в секунду, как мне помнится(специально под скорость оптимизировал).
В этом классе журнал не кольцевой. файл после достижения определенного размера переименовывается и создается новый.


 
AllDer   (2004-01-14 01:23) [26]

В проге поставить выбор,типа
Затирать лог при размере более...
пусть юзер сам думает


 
sniknik   (2004-01-14 08:47) [27]

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


 
Anatoly Podgoretsky   (2004-01-14 09:07) [28]

sniknik © (14.01.04 08:47) [27]
Альтернативные варианты:

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

И выбрать лог текстовый или двоичный, у обоих свои достоинства. Но в любом случае надо предусмотреть паралельную работу лога, на чтение/запись, чтобы не было необходимиости останавливать систему аудитинга.


 
cj Bams   (2004-01-14 18:40) [29]

Вот как я сделал реализацию ведения лога в моей программе


unit uLog;

interface

type
TLog = class(TObject)
private
FLogFileName: string;
FText: Text;
FDate: string;
FPath: string;
FName: string;
FExt : string;
FFirstTime: Boolean;
FLineLength: Integer;
procedure ReAssignFile;
procedure SetLineLength(Value: Integer);
public
constructor Create(ALogFileName: string);
destructor Destroy; override;
procedure LogMsg(msg: string);
procedure LogLine(symbol: Char);
property LineLength: Integer read FLineLength write SetLineLength;
end;

implementation

uses SysUtils, StrUtils;

constructor TLog.Create(ALogFileName: string);
begin
inherited Create();
FLogFileName := ALogFileName;

FDate := DateToStr(Now());

FPath := ExtractFilePath(FLogFileName);
FName := ChangeFileExt(ExtractFileName(FLogFileName),"");
FExt := ExtractFileExt(FLogFileName);

FFirstTime := True;

FLineLength := 50;

ReAssignFile();
end;

destructor TLog.Destroy;
begin
CloseFile(FText);
inherited Destroy();
end;

procedure TLog.ReAssignFile;
var
f: string;
begin
f := FPath + FName +" "+FDate + FExt;

if FFirstTime then begin
if not DirectoryExists(FPath) then ForceDirectories(FPath);
FFirstTime := false;
end else begin
CloseFile(FText);
end;

AssignFile(FText, f);

if FileExists(f)
then Append(FText)
else Rewrite(FText);
end;

procedure TLog.SetLineLength(Value: Integer);
begin
FLineLength := Value;
end;

procedure TLog.LogMsg(msg: string);
var
Dte: string;
begin
Dte:=DateToStr(Now);
if FDate <> dte then begin
FDate := Dte;
ReAssignFile();
end;
Writeln(FText, TimeToStr(Now)+" "+msg);
Flush(FText);
end;

procedure TLog.LogLine(symbol: Char);
var
Dte: string;
begin
Dte:=DateToStr(Now);
if FDate <> dte then begin
FDate := Dte;
ReAssignFile();
end;
Writeln(FText,DupeString(symbol, FLineLength));
Flush(FText);
end;

end.



 
Barbarian five   (2004-01-14 22:41) [30]

2Anatoly Podgoretsky - кольцевой буфер имеет две проблемы: 1. требуется хранение позиции, с которой программа-просмотрщик начинает чтение кольца, 2. теряется часть первой строки/элемента кольца за счет затирания ее хвостом последней записи. Во многих случаях это не сильно исказит картину, но все же...

Хороший вариант - TFileStream.ReadBuffer/WriteBuffer (работает в 100 раз быстрее побайтового/построчного копирования) или Memory Mapping для перемещения больших фрагментов файла лога.

P.S. В многопоточных вариантах не забываем использовать критические секции или мьютексы для разделения доступа к логу!


 
Anatoly Podgoretsky   (2004-01-14 23:32) [31]

Barbarian five (14.01.04 22:41) [30]
Не требуется, есть временные ветки.
Чтение не приносит никаких проблем, а писатель один


 
AllDer   (2004-01-16 01:53) [32]

А если при превышении размера Ч он перименовыв текущ файл в
N.txt и делаете новый лог N+1.txt-где N счетчик ,
при перейш запуске (N=0)храните в реестре N
и файлы будут 0.txt 1.txt ...
если в реестре 8,значит есть 9 файлов 0... 9.txt
и работайте без кольцевой мороки



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.009 c
1-93460
Layner
2004-01-19 11:29
2004.01.29
Посоветуйте StringGrid с обработкой данных как Excel, или создать


1-93520
hStas32ExA
2004-01-18 17:54
2004.01.29
Компонент


14-93658
Knight
2004-01-07 23:44
2004.01.29
Посоветуйте, как можно...


3-93340
SaperXL
2003-12-28 16:13
2004.01.29
Защита БД


1-93472
Tasadar
2004-01-15 21:50
2004.01.29
UTF8, Unicode, UCS4String и т.д.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский