Ucięty plik tekstowy - DLACZEGO !?

0

Może mi ktoś powiedzieć czemu mi logi upieraa w połowie tzn
w pliku mam

+---- START ------- [2012-01-17] [13:44:41] --------------+
[13:44:41] [Application] AppDir [C:\Users\ProQix Polaczeq\Desktop\Tia\Server\Server.exe]
[13:44:41] [Application] Load CFG
[13:44:41] [Plugins Manager] Exec [plugin_in

Po zamknięciu aplikacji nic się nie zmienia
a procedurki za to odpowiedzialne wyglądają tak

procedure TTiaServerBody.LogEvent(Data:String);
begin
 WriteLn(g_EventFile,Data);
end;
procedure TTiaServerBody.LogEventBegin;
begin
 AssignFile(g_EventFile,AppDir+'Logs\'+DateToStr(Date)+' - Events.log');
 if FileExists(AppDir+'Logs\'+DateToStr(Date)+' - Events.log') = True then Append(g_EventFile) else Rewrite(g_EventFile);
 LogEvent(Format('+---- START ------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]));
end;
procedure TTiaServerBody.LogEventEnd;
begin
 LogEvent(Format('+----- END --------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]));
 Sleep(400);
 CloseFile(g_EventFile);
 LogsBox.Items.SaveToFile(AppDir+'Logs\'+DateToStr(Date)+' - Events.log');
end;
LogEvent(Format('[%s] [%s] AppDir [%s]',[TimeToStr(Time),'Application',Application.ExeName]));

podobnie wygląda reszta tylko nie wiem czemu tak ucina?

Ostatnia linia w pliku powinna wyglądać tak
[1357] [Plugins Manager] Exec [plugin_initd] - DLL [C:\WEBServer\Lib\tester.dll]

a Format('+----- END --------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]) nie ma a powinno być

0

pracowicie zapisujesz do pliku, a na koniec robisz LogsBox.Items.SaveToFile(AppDir+'Logs\'+DateToStr(Date)+' - Events.log'); nadpisując to, co wcześniej zapisałeś

0

fakt
LogsBox.Items.SaveToFile(AppDir+'Logs\'+DateToStr(Date)+' - Events.log');
to było dla testu przed tym żeby sprawdzić czy się zapisuje inną metodą i jak tak zapisałem to wleciało wszystko, jednak tego nie mogę używać bo logi muszą być zapisywane na bieżąco bo liczy się ile pracował program i co zrobił zanim się zawiesił/wyłączył albo coś innego (taki debugger). Bo program jest na razie nie stabilny a jak będę tego używał a pozycji będzie max 60 (zwalniam pamięć bo wyobraź sobie 100000 linii do zapisania po 64 B !) to by kasowało poprzednie logi.

0

i słusznie, logów nie trzyma się w pamięci, dopisujesz kolejne linijki do pliku i to wszystko. rozmiarem martwi się administrator. sto tysięcy linijek po kilkaset znaków to raptem kilkadziesiąt MB (w produkcyjnych zastosowaniach logi mogą osiągać rozmiar kilkuset GB i więcej).
sprawdź, czy nie masz wyłączonej opcji "huge strings".

0

to nie ma z tym związku niestety :( (mam CG Delphi 2007 i win 7)

0

Sleep(400);

A to po co?

Zapewne nie używasz zamykania logu i dlatego go obcina bo jest bufor zapisu. Jak log ma działać nawet mimo wykrzaczenia aplikacji to dodaj po writeln flush(plik); (zapisze bufor).

I BTW. naprawdę dopiski w temacie typu "DLACZEOG !?" są niepotrzebne a nawet niewskazane. Zachowuj się porządnie...

0

@proqix, dlaczego wybrałeś takie rozwiązanie (pozwoliłem sobie sformatować kod, bo niewiele w nim widziałem):

procedure TTiaServerBody.LogEvent(Data: String);
begin
  WriteLn(g_EventFile, Data);
end;

procedure TTiaServerBody.LogEventBegin;
begin
  AssignFile(g_EventFile, AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');

  if FileExists(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log') then
    Append(g_EventFile)
  else
    Rewrite(g_EventFile);

  LogEvent(Format('+---- START ------- [%s] [%s] --------------+', [DateToStr(Date), TimeToStr(Time)]));
end;

procedure TTiaServerBody.LogEventEnd;
begin
  LogEvent(Format('+----- END --------- [%s] [%s] --------------+', [DateToStr(Date), TimeToStr(Time)]));
  Sleep(400);

  CloseFile(g_EventFile);
  LogsBox.Items.SaveToFile(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');
end;

??? Trochę to dziwne, że używasz takiej konstrukcji; Czy klasa TTiaServerBody jest w całości napisana przez Ciebie? Bo jeżeli tak, to czemu wykorzystujesz g_EventFile jako zmienną globalną? Czy g_EventFile jest polem prywatnym?

Musisz się zastanowić nad tym zapisem i zrobić (tak jak Ci podpowiada @123) Flush(g_EventFile);, albo po prostu otwierać i zamykać plik każdorazowo, jak trzeba zapisać doń jakieś informacie; Wiadomo, ten sposób będzie mało wydajny, ale mniej błędny; Zrób trzy procedury:

  1. do wpisywania początku logu
  2. do wpisywania aktualnych wartości logu
  3. do wpisywania zakończenia logu
    i sprzęż je tak, by argumentem była wartość, a otwieranie i zamykanie pliku było oprogramowane tylko raz:
procedure TTiaServerBody.SaveLogEvent(Data: String);
begin
  AssignFile(g_EventFile, AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');

  try
    if FileExists(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log') then
      Append(g_EventFile)
    else
      Rewrite(g_EventFile);

    WriteLn(g_EventFile, Data);
  finally
    CloseFile(g_EventFile);
  end;
end;

procedure TTiaServerBody.LogEventBegin();
begin
  SaveLogEvent(Format('+---- START ------- [%s] [%s] --------------+',
               [DateToStr(Date), TimeToStr(Time)]));
end;

procedure TTiaServerBody.LogEventBegin();
begin
  SaveLogEvent(Format('+----- END --------- [%s] [%s] --------------+',
               [DateToStr(Date), TimeToStr(Time)]));
  Sleep(400);
  LogsBox.Items.SaveToFile(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');
end;

Co Ty na to?

0

g_EventFile : TextFile jest w głównym varze (tak gdzie TiaServerBody: TTiaServerBody;) procedury zadeklarowane w public, ja potrzebuje wydajności !
LogEventBegin; jest używany w OnCreate formy a LogEventend; w OnClose, LogEvent jest wykorzystywany przez inne formy (Unity).

Jak pisałem w wyżej LogsBox.Items.SaveToFile(AppDir + 'Logs' + DateToStr(Date) + ' - Events.log'); użyłem by sprawdzić czy się zapisuje dobrze jak użyję domyślnej procedury, bo muszę często opróżniać pamięć bo raz przy włączeniu programu poszedłem do kibla a jak wruciłem to miałem 200kB logów oczywiście ostatnia linia została ucięta :(

0
proqix napisał(a)

g_EventFile : TextFile jest w głównym varze (tam gdzie TiaServerBody: TTiaServerBody;) procedury zadeklarowane w public

To błąd, wiesz przecież, że nie zaleca się korzystania ze zmiennych globalnych... Czy te procedury masz zadeklarowane w sekcji public klasy formularza? Bo jeżeli tak, to wg mnie źle to przemyślałeś; Polecam bardzo gorąco utworzyć osobną klasę, w której zaimplementujesz obsługę pliku log; Dzięki temu unikniesz bałaganu w kodzie i w jedym obiekcie zawrzesz i metody do obsługi pliku log i zmienną plikową, która będzie widoczna tylko w obrębie modułu klasy (czyli w sekcji private klasy); Dzięki temu bezpośrednio nie będzie można dokonywać modyfikacji na zmiennej plikowej, a metody, które służą do zapisywania poszczególnych linii w pliku będą mogły swobodnie z niej korzystać;

ja potrzebuje wydajności !

Z jaką częstotliwością będzie realizowane zapisywanie linii do pliku?

@ Ta linia:

LogsBox.Items.SaveToFile(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');

będzie Ci nadpisywać zawartość wcześniej uzupełnionego pliku; Trzeba ją usunąć (a może ja ją niepotrzebnie wkleiłem do kodu..?);

0

@ tak ona była dla testu,
@ co do częstotliwości to zależny czy błędy się będą sypać jak lawina pomijając logi ważnych zmiennych takich ja użycie procedury/funkcji z bibliotek (pluginów)
jeżeli chodzi o zamknięcie loggera w osobnej klasie to nie myślałem o tym gdyż to małe czynności są ;] ale zaraz zrobię to i zobaczymy

1
proqix napisał(a)

@ co do częstotliwości to zależny czy błędy się będą sypać jak lawina pomijając logi ważnych zmiennych takich ja użycie procedury/funkcji z bibliotek (pluginów)

A tak mniej więcej? Jakie maksimum przewidujesz? Kilka, kilkanaście, kilkaset na sekundę? Mniej więcej; Bo jeżeli będzie ich maksymalnie kilka, to nie musisz się bać, że program będzie się dławił, jak za każdym razem gdy chcesz zapisać coś w pliku będziesz go otwierał i zamykał;

Zawsze możesz przeprowadzić test na klasie - zapuść pętlę na 10.000 iteracji, w której będziesz odpowiednio:

  1. otwierał plik
  2. zapisywał linię
  3. zamykał plik
    i zobacz, w jakim czasie on to wykona; Później oblicz ile możesz takich operacji wykonać, żeby program się nie przycinał;

Jeżeli wszystko będzie w porządku - skorzystaj z takiego rozwiązania :)

proqix napisał(a)

jeżeli chodzi o zamknięcie loggera w osobnej klasie to nie myślałem o tym gdyż to małe czynności są

Owszem, ale przejżystość kodu wzrośnie co jest atutem;

@ Naszkicowałem Ci przykładową klasę do obsługi pliku log (kod modułu):

unit uLogFileSupport;

interface

uses
  SysUtils;

type
  TLogFileSupport = class(TObject)
  private
    FLogFileName: String;
  public
    constructor Create(LogFileName: String);
    destructor Destroy(); override;

    procedure LogEvent(Event: String);
    procedure BeginLog();
    procedure EndLog();
  end;

implementation

  constructor TLogFileSupport.Create(LogFileName: String);
  begin
    inherited Create();

    FLogFileName := LogFileName;
  end;

  destructor TLogFileSupport.Destroy();
  begin
    inherited Destroy();
  end;

  procedure TLogFileSupport.LogEvent(Event: String);
  var
    fLogFile: TextFile;
  begin
    AssignFile(fLogFile, FLogFileName);

    try
      case FileExists(FLogFileName) of
        True:  Append(fLogFile);
        False: ReWrite(fLogFile);
      end;

      WriteLn(fLogFile, Event);
    finally
      CloseFile(fLogFile);
    end;
  end;

  procedure TLogFileSupport.BeginLog();
  begin
    LogEvent(Format('+---- START ------- [%s] [%s] --------------+',
                    [DateToStr(Date), TimeToStr(Time)]));
  end;

  procedure TLogFileSupport.EndLog();
  begin
    LogEvent(Format('+----- END --------- [%s] [%s] --------------+',
                    [DateToStr(Date), TimeToStr(Time)]));
  end;

end.

Tworzenie i usuwanie obiektu (odpowiednio podczas tworzenia i niszczenia formularza):

procedure TForm1.FormCreate(Sender: TObject);
begin
  lfsLog := TLogFileSupport.Create(AppDir + 'Logs\' + DateToStr(Date) + ' - Events.log');
  lfsLog.BeginLog();
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  lfsLog.EndLog();
  lfsLog.Free();
end;

Wpisywanie zdarzenia do pliku:

lfsLog.LogEvent('Treść zdarzenia');

Klasa przetestowana i działa w 100%; Uruchomienie aplikacji, trzykrotne zapisanie zdarzenia i zamknięcie aplikacji spowodowało zapisanie do pliku treści:

+---- START ------- [2012-01-17] [21:34:49] --------------+
Treść zdarzenia
Treść zdarzenia
Treść zdarzenia
+----- END --------- [2012-01-17] [21:34:52] --------------+

Wszystko pięknie; Może być taka konstrukcja? :)

0

to tak zrobiłem do tego osobny unit żeby było ładnie i fajnie

unit QLogger;

interface

uses Dialogs, SysUtils, Classes, Body ;

type TLogger = class(TComponent)
     procedure LogEventBegin(Dir:String);
     procedure LogEventEnd;
     procedure LogEvent(Data:String);
end;

var
  Logger        : TLogger;
  EventFile : TextFile;
implementation

procedure TLogger.LogEvent(Data:String);
begin
 TiaServerBody.LogsBox.Items.Add(Data);
 WriteLn(EventFile,Data);
end;

procedure TLogger.LogEventBegin(Dir:String);
begin
 AssignFile(EventFile,Dir);
 if FileExists(AppDir+'Logs\Events.log') = True then Append(EventFile) else Rewrite(EventFile);
 LogEvent('');
 LogEvent(Format('+---- START ------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]));
end;

procedure TLogger.LogEventEnd;
begin
 LogEvent(Format('+----- END --------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]));
 Sleep(400);
 Flush(EventFile);
 CloseFile(EventFile);
end;

end.

W OnCreate formy dałem Logger.LogEventBegin(Dir);
fajnie plik utworzyło ale dalej jest jak było nie wiedzieć czemu

log tak wygląda po uruchomieniu i zamknięciu

+---- START ------- [2012-01-17] [2139] --------------+
[2139] [Application] dir [C:\Tia\Server\Server.exe]
[2139] [Application] Loading configs
[2140] [Plugins Manager] Exe [plugin_initd] at plugin [C:\Tia\Plugins\CMDConsole\CMDConsole.dll]
[2140] [Plugins Manager] Load 1 p

@Logować się będzie szybko i to by wystarczało ale to były by testy bez obciążenia bo nie wiem ile tych gówienek się uruchomi (chociażby konsole cmd z pluginu tak ze 300 będzie pracować nie mówiąc o reszcie) to jak program się przytnie to koniec a ciężko mi określić co się będzie na tym wyprawiać...

0
proqix napisał(a)

@Logować się będzie szybko i to by wystarczało ale to były by testy bez obciążenia bo nie wiem ile tych gówienek się uruchomi (chociażby konsole cmd z pluginu tak ze 300 będzie pracować nie mówiąc o reszcie) to jak program się przytnie to koniec a ciężko mi określić co się będzie na tym wyprawiać...

Nie rozumiem zbytnio o co Ci w tym zdaniu chodziło...

Czyli jednak wolisz fluszować :)

Dodatkowo napiszę, że przetestowałem móją klasę; Wynik jest wystarczający, bo wykonanie 1000 razy zapisu zdarzenia do pliku (według mojego sposobu) zajęło mniej niż sekundę (sprzęt IBM R31, 1.13GHz, 512 RAM, HDD Samsung HM160HC 160Gb); Nie sądzę, żebyś musiał aż tyle razy zapisywać zdarzenie do dziennika;

@ Zauważyłeś, że Twój log nie ma ostatniej linii?

Procedurę Flush powinieneś w tym wypadku używać każdorazowo po wpisaniu zdarzenia do dziennika, czyli zamiast używania jej tutaj:

procedure TLogger.LogEventEnd;
begin
  LogEvent(Format('+----- END --------- [%s] [%s] --------------+',[DateToStr(Date),TimeToStr(Time)]));
  Sleep(400);
  Flush(EventFile);
  CloseFile(EventFile);
end;

umieść ją tu:

procedure TLogger.LogEvent(Data:String);
begin
  TiaServerBody.LogsBox.Items.Add(Data);
  WriteLn(EventFile,Data);
  Flush(EventFile);
end;

Będzie działać bez problemów;

0

Dobra, dzięki za pomoc wszystko działa poprawnie przy wsparciu części twojego kodu.
A co do

Nie rozumiem zbytnio o co Ci w tym zdaniu chodziło...

Program posiada biblioteki DLL (pluginy) i w nich zachodzą różne różności np w CMDConsole.dll do tablicy ładowane są dynamicznie stworzone komponenty do obsługi konsoli CMD i ta biblioteka to kontroluje (wysyłanie opleceń, odbieranie poleceń, tworzenie i usuwanie komponentów), w innej bibliotece będzie obsługa graficznego pulpitu (coś jak zdalny pulpit z MS Windows) w innej będzie zarządzanie zasilaniem. Ogółem program ma działać jak coś trojan ;] , dlatego zabaw a w pluginy bo mi się nie chce bawić w kompilacje całości za każdym razem, tym bardziej że w większości pisze to na lekcjach informatyki czy na przerwach w szkole gdzie nie mam dostępu do Delphi tylko notatnika itp niskich narzędzi ;]

1 użytkowników online, w tym zalogowanych: 0, gości: 1