Dodanie parametru do procedury - logi programu

0

Witam proszę o pomoc w następującej kwestii. Staram sie zmodyfikować procedurę zbierającą logi programu, chodzi o dodanie jeszcze jednego parametru typu integer określającego "priorytet" danego komunikatu. Za dodawanie Logów odpowiadają następujące procedury.

procedure TUstawienia.Log(const Msg: String);
begin
  if not Assigned(LLogProgress) then
    Exit;
    LLogProgress.Items.Insert(0,(dateToStr(date))+'. '+(TimeToStr(time))+'. '+Msg);
    LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
end;

procedure TUstawienia.Log(const Msg: String; const Args: array of const);
begin
  Log(format(Msg, Args));
end;

Dodawanie Komunikatu do LLogProgress odbywa sie poprzez:

Log('Komuniat !!!!');

Chodzi mi o dodanie jeszcze jednego parametru typu integer ktory określał by priorytet komunikatu, najlepiej by całość wyglądała tak:

Log('Komuniat !!!!',1); 

Gdzie 1 to właśnie ten priorytet. Ma to na celu umożliwienie filtrowanie wyświetlania wszystkich komunikatów badz tylko najważniejszych. Ustawienie priorytetów komunikatów odbywa sie poprzez wybór z comboboxa.

procedure TUstawienia.ComboBox1Change(Sender: TObject);
begin
case ComboBox1.ItemIndex of
    0:priorytet:=1;  //dodaje wszystkie komniaty
    1:priorytet:=2;  //dodaje wazne  komunikaty
    2:priorytet:=3;  //dodaje tylko najwazniejsze komunikaty
end;

I tak wybór np. pierwszego itemu powoduje dodanie komunikatów wszystkich tzn 1+2+3, drugiego 2+3, trzeciego tylko 3. Mam nadzieje ze nie namieszałem i w miarę wiadomo o co chodzi. Z góry dziękuje za pomoc.

0

Jeżeli dobrze zrozumiałem o co chodzi, to najprościej można obyć się bez dodatkowego parametru, tylko kontrolować wprost ComboBox1.ItemIndex

procedure TUstawienia.Log(const Msg: String);
begin
  if not Assigned(LLogProgress) then
    Exit;
  case ComboBox1.ItemIndex of
    0: //dodaje wszystkie komniaty
    1: //dodaje wazne  komunikaty
    2: //dodaje tylko najwazniejsze komunikaty
  else
    //jakiś błąd
  end;
//...
end;
0

Tak nawiasem - ten kod:

procedure TUstawienia.ComboBox1Change(Sender: TObject);
begin
case ComboBox1.ItemIndex of
    0:priorytet:=1;  //dodaje wszystkie komniaty
    1:priorytet:=2;  //dodaje wazne  komunikaty
    2:priorytet:=3;  //dodaje tylko najwazniejsze komunikaty
end;

chyba prościej zapisać tak:

procedure TUstawienia.ComboBox1Change(Sender: TObject);
begin
  Priorytet := Succ(ComboBox1.ItemIndex);
end;

prawda? Jednak tak, jak wspomniał @pelsta - prościej od razu obsłużyć ItemIndex bez zbędnych zmiennych pomocniczych i przeypisywania;


Trochę mało napisałeś na temat Twojego modelu logowania, np. czym jest magiczny LLogProgress i co to ma wspólnego z progresem (postępem)? To jest wirtualny (niewidoczny) obiekt czy kontrolka? I dlaczego podczas dodawania nowego komunikatu sprawdzasz istnienie tego obiektu? I gdzie chcesz przedstawić listę tych komunikatów (gdzie chcesz ją wyświetlić)?

Gdybym sam miał stworzyć taki mechanizm logów, to wykorzystałbym obiektowość i stworzył klasę zawierającą wszystkie potrzebne informacje na temat logów; Przede wszystkim podzieliłbym logi na trzy listy dla każdego priorytetu i z nich ładował logi do kontrolki według zadanych kryteriów.

0

No można ale to czy priorytet będzie określony przez index czy przez np index comboboxa to najmniejszy problem, nie bardzo wiem jak zmodyfikować procedure wywołania komunikatu by dodać do niej znacznik danego priorytetu.

0

Napisz sobie klasę do przechowywania i obsługi logów - w niej zaimplementujesz trzy listy logów, np. klasy TObjectList; W klasie silnika logów tworzysz pole jako macierz z trzema elementami - trzema listami dla każdego priorytetu i do odpowiednich list odwołujesz się przez przygotowane procedury/funkcje/właściwości; Przy wyświetlaniu listy w kontrolce jako argument podajesz priorytet, który będzie indeksem do odpowiedzniej listy, a jako drugi argument podajesz kontrolkę, w której ma być wyświetlona; Dzięki tym argumentom możesz elegancko w pętli wyświetlić wszystkie itemy-logi z danej listy;


EDIT: Jak będę miał chwilkę czasu to naskrobię Ci przykładowy silnik do obsługi logów z kilkoma priorytetami wykorzystując OOP; Dorzucę Ci gratis prosty edytorek do dodawania i przeglądania listy logów.

0

Tak myślałem ze bez osobnej klasy się nie obędzie, co prawda nie na ta zaawansowanym poziomie jak opisałeś ale spróbuję. A za przykład będę bardzo wdzięczny.

2

Skoro piszesz w środowisku obiektowym, to wykorzystuj w pełni jego możliwości - twórz klasę zawsze gdy sytuacja tego wymaga, a tutaj wymaga; Klasa do obsługi logów bardzo uprości cały proceder tworzenia, przechowywania i wyświetlania logów; Będziesz ją mógł w prosty sposób modyfikować unowocześniać o nowe funkcjonalności itd., a przy okazji pouczysz się trochę obiektowości; Dlatego warto w tym wypadku stworzyć taką klasę.


EDIT: W załączniku dodaję prostą aplikację zarządzającą silnikiem logów; Klasa do obsługi logów jest bardzo skromna - zaimplementowałem tylko dodawanie nowych logów i ich wyświetlanie w kontrolce klasy TListBox, ale bez problemu można ją unowocześnić o usuwanie i modyfikowanie poszczególnych logów, czyszczenie list, modyfikowanie priorytetów logów (a tym samym przeniesienie ich do odpowiedniej listy), sortowanie list, eksport do i import z plików itd. itd.;

Przeanalizuj sobie program, a przede wszystkim klasy:

  • TLogInfo - zawiera informacje na temat pojedynczego logu,
  • TLogEngine - silnik obsługujący trzy listy logów dla danych priorytetów;
    reszta programu to zabiegi kosmetyczne w celu obsługi silnika logów oraz formularza z listą do ich wyświetlania; Pliki:

LogEngine_project.zip: https://www.virustotal.com/en/file/c6f5b6694d51ae34022923fdee7d9706c1f3dd52db3872a3eca0bc85eb1f0123/analysis/1365417243/
LogEngine_exe.zip: https://www.virustotal.com/en/file/5177a467d246a0d17d9785d133313814333beafb5b9f7d6bd05706d0f3da93f8/analysis/1365417742/

były skanowane na VirusTotal - brak zagrożeń;


To jest tylko przykład prostego silnika do obsługi logów - to nie gotowiec, więc kodu nie skopiujesz i nie wkleisz w swoim projekcie; Aby go wykorzystać musisz zrozumieć jak działa i przepisać go do swojego programu przystosowując silnik pod własne wymagania.

0

Ja dla mnie mechanizm na wypasie, postaram się oprzeć na nim mój mechanizm logów, dzięki wielkie za ogromna pomoc.

0

To tylko zalążek klasy - żeby była w pełni funkcjonalna wypada wyposażyć ją w więcej metod, przede wszystkim do modyfikacji pojedynczych logów; Nie miałem zbyt wiele czasu dlatego utworzyłem jedną funkcję do odczytu i jedną do zapisu loga zamiast właściwości, które powinny określać typ dostępu do poszczególnych pól klasy; Można to oczywiście samemu według własnego uznania zaimplementować, co będzie teraz Twoim zadaniem w ramach nauki obiektowości;


EDIT: W swoim początkowym mechanizmie każdy nowy log był wstawiany na początek listy (lista działała na zasadzie stosu), a w podanym przeze mnie przykładzie na końcu listy; Tak więc jeśli chcesz to możesz odwrócić odczytywanie logów z list podczas ich wyświetlania w kontrolce klasy TListBox; Wtedy będziesz miał najmłodszy log na samej górze kontrolki, a najstarszy na samym dole.

1
furious programming napisał(a):

w niej zaimplementujesz trzy listy logów
Tworzenie tylu list ile priorytetów? Przecież to znacznie utrudnia operacje takie jak usuwanie ostatniego loga / ostatnich x-tysięcy logów.

Usuń pierwszy element listy raz czy tysiąc razy a sprawdź wszystkie listy pod kątem ostatniego loga, usuń go i tak wiele razy.

furious programming napisał(a):

ale bez problemu można ją unowocześnić o usuwanie i modyfikowanie poszczególnych logów
Modyfikacja loga?
Mam nadzieję, że użyłeś złego określenia na zmodyfikowanie sposobu wyświetlenia loga (tło itd.).

Jeśli nie, to ty chcesz oszukiwać usera? Najpierw pokażesz mu w logu, że wystąpił poważny błąd, a potem zmienisz to na skromne: "X lekko spanikował", gdzie X to ty lub program? bezsens.
Jak już chcesz coś ukrywać to pozostań przy usuwaniu takiego loga lub nie pokazywaniu go wcale.


W zależności od potrzeb, system logów powinien móc: * dodawać/usuwać log * usuwać ostatni log lub x logów po przekroczeniu jakiegoś limitu (np. chcesz pokazywać ostatnie 2000 logów) * filtrować logi wg pewnych kryteriów * zapis listy logów do pliku np. `.txt` * ... Filtrować można wg czegoś, więc jeśli chcesz filtrować logi wg priorytetu, to twój obiekt/rekord musi zawierać odpowiednie informacje potrzebne ku temu. Możesz pozostać tylko przy treści wiadomości, ale takie minimum to:

Log
enum/int Typ
string Wiadomość
DateTime CzasDodania

Typ - np. ostrzeżenie, błąd, zwykła wiadomość; wg tego możesz zastosować odpowiedni styl do wyświetlenia tego wpisu.


Ewentualnie możesz stworzyć listy wskaźników, które odpowiednio będą wskazywać na konkretne wpisy. Owe listy synchronizujesz z każdą operacją dodania/usunięcia elementu do/z głównej listy.

Dodanie do głównej = dodanie wskaźnika do odpowiedniej "sub"-listy.
Usunięcie z głównej = usunięcie wskaźnika.

Na twoim miejscu opierałbym się tylko na jednej, głównej liście logów. Tyle, że ta lista ma być obiektem, w którym będą przechowywane logi, a z każdą zmianą tego obiektu, system logów będzie aktualizować twojego ListBoxa.

0

Ok zeby było wiadomo jeszcze raz wyjaśnię. W chwili obecnej mam już system dodawania logów sa one zapisywane i odczytywane z ini na podstawie aktualnej daty (program sprawdza w tracie uruchomienia czy dany dzień w logach istnieje jesli ta wczytuje logi jeśli nie tworzy nowa sekcje). W programie będzie łącznie kilkaset zdarzeń generujących logi, oczywiście jedne sa ważne inne mniej. Nie chodzi mi o to by zapisywać wszystkie ale by po wybraniu z comboboxa jednej z opcji zapisywał tylko ważne bądź wszystkie. Cos na zasadzie:

if priorytet=3 then Log('Dodaje wszystkie komunikaty');

Lub

if priorytet=1 then Log('Dodaje wazne kounikaty');

Za dodawanie komunikatów odpowiada:

procedure TUstawienia.Log(const Msg: String);
begin
  if not Assigned(LLogProgress) then
    Exit;
    LLogProgress.Items.Insert(0,(dateToStr(date))+'. '+(TimeToStr(time))+'. '+Msg);
    LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
end;
 
procedure TUstawienia.Log(const Msg: String; const Args: array of const);
begin
  Log(format(Msg, Args));
end;

Natoiast same komunikaty w poszczególnych zdarzeniach przekazuje tak:

Log('Komuniat !!!!');

Czy istnieje w miarę malo inwazyjny sposób ponieważ siedzę nad tymi logami już kilka dni zmodyfikowania procedury dodawania logów tak by przed dodaniem logu sprawdzał jaka opcja została wybrana w coboboxie sprawdzał jaki priorytet ma dany log na podstawie integera i dodał lub zignorował komunikat.
Oczywiście samo wywołanie powinno być opatrzone dodatkowym parametrem który stanowił by kontrolkę dodania bądź zignorowania komunikatu.

Log('Komuniat !!!!',1);//gdzie integer 1 stanowi kontrolkę.
0

Tworzenie tylu list ile priorytetów? Przecież to znacznie utrudnia operacje takie jak usuwanie ostatniego loga / ostatnich x-tysięcy logów.

Równie dobrze można stwierdzić, że jedna lista tak samo znacznie utrudnia wyświetlanie logów z zadanego priorytetu - bezsens;

Usuń pierwszy element listy raz czy tysiąc razy a sprawdź wszystkie listy pod kątem ostatniego loga, usuń go i tak wiele razy.

No faktycznie trzeba przeszukać wszystkie trzy listy żeby znaleźć ostatni dodany wpis... Jakby nie można porównać ostatnich itemów z każdej listy i sprawdzić, który jest ostatni; Tylko nie zapominaj, że pytacz chce móc pokazywać na liście logi danego priorytetu bądź wszystkie - o to pytał, więc pod tym kątem zaproponowałem algorytm; Gdyby jasno były przedstawione wszystkie funkcjonalności systemu logów to sporządziłoby się pewnie inny system; Nie wiem jakie mają być wszystkie funkcje, więc nie wiem na 100% co zaproponować, dlatego też podałem rozwiązanie stworzone głównie dla łatwości filtrowania logów jedynie pod kątem priorytetu; Poza tym zwykły szary użytkownik nie ma zielonego pojęcia co dzieje się "pod maską" aplikacji - jego interesuje jedynie część wizualna, więc równie dobrze list może być trzy, a wyświetlanie ich w kontrolce klasy TListBox może być dostosowane pod oko użytkownika;

Modyfikacja loga?
Mam nadzieję, że użyłeś złego określenia na zmodyfikowanie sposobu wyświetlenia loga (tło itd.).

Jeśli nie, to ty chcesz oszukiwać usera? Najpierw pokażesz mu w logu, że wystąpił poważny błąd, a potem zmienisz to na skromne: "X lekko spanikował", gdzie X to ty lub program? bezsens.
Jak już chcesz coś ukrywać to pozostań przy usuwaniu takiego loga lub nie pokazywaniu go wcale.

Polecam przestać siać panikę i doszukiwać się spisków i oszustw; Modyfikować logi można na wiele sposobów i wielu celach, a Ty od razu zakładasz oszukanie użytkownika i robienie z niego wała; Zastanów się może najpierw do czego mogłaby się przydać modyfikacja loga, a później wysuwaj swoje spekulacje;


@tayamoto - może przedstaw jasno wszystkie funkcjonalności jakie powinien mieć Twój system logów, a wtedy dokładnie określi się co należy zaimplementować w klasie; Nie wspomniałeś o tym, że potrzebujesz wyświetlić logi np. posortowane według daty ich dodania, ale jeśli faktycznie to by się przydało, to można wykorzystać tylko jedną listę klasy TObjectList i zmodyfikować klasę TLogInfo, a raczej dodać do niej pole, w którym przechowywane będą informacje na temat priorytetu danego loga, np.:

type
  TLogPriority = (lpLow, lpMedium, lpHigh);

{...}

type
  TLogInfo = class(TObject)
  private
    FPriority: TLogPriority;
    FDateTime: TDateTime;
    FMessage: AnsiString;
  public
    constructor Create(const APriority: TLogPriority;
                       const ADateTime: TDateTime;
                       const AMessage: AnsiString);
    destructor Destroy(); override;
  public
    property Priority: TLogPriority read FPriority;
    property DateTime: TDateTime read FDateTime;
    property Message: AnsiString read FMessage;
  public
    function GetLog(): AnsiString;
  end;

Podczas wyświetlania logów z danego priorytetu lub grupy priorytetów jedziesz w pętli po wszystkich itemach listy i sprawdzasz, czy dany log posiada priorytet, pod kątem którego odbywa się wyszukiwanie; Wystarczy nieco zmodyfikować pętlę wyszukującą oraz zadeklarować sobie nowy typ, który będzie zbiorem priorytetów, np.:

type
  TLogPriority = (lpLow, lpMedium, lpHigh);
  TLogPrioritySet = set of TLogPriority;

TLogPrioritySet jest zbiorem priorytetów dla wyświetlanych logów; Taki zbiór podajesz w argumencie metody ShowLogs(), a w pętli wyszukującej sprawdzasz czy priorytet danego loga istnieje w podanym zbiorze; Jeśli tak - dodajesz do kontrolki, jeśli nie - pomijasz go i sprawdzasz następny;


Tak więc napisz wszystko co ma posiadać system logów, a dostosuje się klasę silnika pod te wymagania.

0
furious programming napisał(a):

Tworzenie tylu list ile priorytetów? Przecież to znacznie utrudnia operacje takie jak usuwanie ostatniego loga / ostatnich x-tysięcy logów.

Równie dobrze można stwierdzić, że jedna lista tak samo znacznie utrudnia wyświetlanie logów z zadanego priorytetu - bezsens;

Bezsens to będzie jak ci się zachcę pokazać wszystkie logi i to z każdą zmianą list. Wybierając między:

  • wykonaj pętlę, wyświetlając wpisy z priorytetem X z jednej listy
  • wykonaj pętlę, w której wyświetlisz wpisy posortowane wg daty dodania z wielu list
    wybrałbym to pierwsze szczególnie, jeśli nie wiem ile razy będę musiał filtrować bądź nie listę.
furious programming napisał(a):

Usuń pierwszy element listy raz czy tysiąc razy a sprawdź wszystkie listy pod kątem ostatniego loga, usuń go i tak wiele razy.

No faktycznie trzeba przeszukać wszystkie trzy listy żeby znaleźć ostatni dodany wpis... Jakby nie można porównać ostatnich itemów z każdej listy i sprawdzić, który jest ostatni; Tylko nie zapominaj, że pytacz chce móc pokazywać na liście logi danego priorytetu bądź wszystkie - o to pytał, więc pod tym kątem zaproponowałem algorytm; Gdyby jasno były przedstawione wszystkie funkcjonalności systemu logów to sporządziłoby się pewnie inny system; Nie wiem jakie mają być wszystkie funkcje, więc nie wiem na 100% co zaproponować, dlatego też podałem rozwiązanie stworzone głównie dla łatwości filtrowania logów jedynie pod kątem priorytetu; Poza tym zwykły szary użytkownik nie ma zielonego pojęcia co dzieje się "pod maską" aplikacji - jego interesuje jedynie część wizualna, więc równie dobrze list może być trzy, a wyświetlanie ich w kontrolce klasy TListBox może być dostosowane pod oko użytkownika;

Skąd sobie ubzdurałeś, że sprawdzałbym każdy wpis loga z wielu list i wybierał z nich ten ostatni? Napisałeś, że nie wiesz jaki ostatecznie będzie ten system, czemu trzymasz się magicznej cyfry 3? To, że teraz w fazie początkowej pytający ustalił 3 priorytety albo, że podał dla prostoty zrozumienia tego, co chcę zrobić zakres 1-3 nie oznacza, że finalnie nie będzie więcej priorytetów. Skoro nic nie wiemy dokładnie, to czemu się ograniczasz?
Odpowiedz sobie na te pytania, a dowiesz się czemu obecnie twój sposób rozwiązania problemu nie jest najlepszy.

furious programming napisał(a):

Modyfikacja loga?
Mam nadzieję, że użyłeś złego określenia na zmodyfikowanie sposobu wyświetlenia loga (tło itd.).

Jeśli nie, to ty chcesz oszukiwać usera? Najpierw pokażesz mu w logu, że wystąpił poważny błąd, a potem zmienisz to na skromne: "X lekko spanikował", gdzie X to ty lub program? bezsens.
Jak już chcesz coś ukrywać to pozostań przy usuwaniu takiego loga lub nie pokazywaniu go wcale.

Polecam przestać siać panikę i doszukiwać się spisków i oszustw; Modyfikować logi można na wiele sposobów i wielu celach, a Ty od razu zakładasz oszukanie użytkownika i robienie z niego wała; Zastanów się może najpierw do czego mogłaby się przydać modyfikacja loga, a później wysuwaj swoje spekulacje;

Modyfikować to możesz postęp w progressBarze albo w stringu oznaczającym prędkość pobierania, albo właściwości obiektu trzymającego informację o aktualnie pobieranym pliku.
Chcesz modyfikować log, bo zapomniałeś kropki? Tak za każdym razem, bo nie chciało ci się zakodzić kropki w stringu?
Odpowiedz mi - czemu chcesz edytować wpis zawierający informację o zdarzeniu, które się stało i się już nie zmieni, a które jedynie może się powtórzyć?

0

Skąd sobie ubzdurałeś, że sprawdzałbym każdy wpis loga z wielu list i wybierał z nich ten ostatni?

Z tego samego miejsca, co Ty ubzdurałeś sobie oszukiwanie użytkownika;

Napisałeś, że nie wiesz jaki ostatecznie będzie ten system, czemu trzymasz się magicznej cyfry 3?

Nie wiem jak dokładnie ma wyglądać system pod kątem funkcjonalności, zaś ilość priorytetów jest jasno określona przez pytacza już w pierwszym poście; Więc nie trzymam się rękami i nogami magicznej liczby 3, tylko realizuję choć jedno "pewne" założenie systemu;

Modyfikować to możesz postęp w progressBarze albo w stringu oznaczającym prędkość pobierania, albo właściwości obiektu trzymającego informację o aktualnie pobieranym pliku.
Chcesz modyfikować log, bo zapomniałeś kropki? Tak za każdym razem, bo nie chciało ci się zakodzić kropki w stringu?

Ty mnie nie ucz co można modyfikować a co nie, bo dobrze zdaję sobie z tego sprawę, a Twoje argumenty nie dotyczą w ogóle poruszanego tematu;

Odpowiedz mi - czemu chcesz edytować wpis zawierający informację o zdarzeniu, które się stało i się już nie zmieni, a które jedynie może się powtórzyć?

Nie chcę, a mogę - a to różnica; Nie zmuszam pytacza do zaimplementowania tego w swoim programie; A dlaczego i po co mógłbym je modyfikować? Jest co najmniej kilka powodów, dla których można by to wykonać; Choćby po to, by poinformować użytkownika o nowych-nieprzeczytanych logach, o tym, że zaraportowany błąd został poprawiony przez aplikację i ma wyświetlić przy logu fajeczkę, a nie krzyżyk itd.; Jest wiele sytuacji, w których modyfikacja danego loga służy do informowania użytkownika, a nie do oszukiwania go, a to, że inne aplikacje być może tego nie wykorzystują to nie jest żaden powód, by nie stosować tego w swoim systemie.

0
WinFormsApp1 napisał(a):

Modyfikacja loga?
Mam nadzieję, że użyłeś złego określenia na zmodyfikowanie sposobu wyświetlenia loga (tło itd.).

furious programming napisał(a):

zaraportowany błąd został poprawiony przez aplikację i ma wyświetlić przy logu fajeczkę, a nie krzyżyk itd.

Zmienianie treści loga, a sposobu w jaki zostanie wyświetlony to dwie różne rzeczy. Wolałeś się kłócić, zamiast przyznać racje lub pozostać bez komentarza.


furious programming napisał(a):

by poinformować użytkownika o nowych-nieprzeczytanych logach

Nie myl loga ze statusem.
Status się zmienia, a log nie - co najwyżej dochodzi nowy:

WinFormsApp1 napisał(a):

wpis zawierający informację o zdarzeniu, które się stało i się już nie zmieni, a które jedynie może się powtórzyć

Status poprawnie powinien zostać zamieniony na X logów, gdzie X oznacza ile razy normalnie został by odświeżony. Udawanie statusu przez log to moim zdaniem porażka systemu. Trzeba wiedzieć co i kiedy nadaje się do wstawienia jako log, albo do zaimplementowania jako status (zazwyczaj pokazywany w dolnej części aplikacji).
Oczywiście można wymyślać jakieś mieszańce, ale temat jednoznacznie wskazuje, że chodzi o logi.


furious programming napisał(a):

Twoje argumenty nie dotyczą w ogóle poruszanego tematu;
Nie zmuszam pytacza do zaimplementowania tego w swoim programie;

Nie zmuszasz, ale proponujesz, więc cała ta nasza dyskusja ma sens i dotyczy wątku. Dodawanie opcji modyfikacji loga (jego treści) jest więcej niż niepotrzebne.


*Albo ja nie umiem dobrze pisać, albo twoje szybkie czytanie nie idzie koniecznie w parze ze zrozumieniem.*
0

Zmienianie treści loga, a sposobu w jaki zostanie wyświetlony to dwie różne rzeczy. Wolałeś się kłócić, zamiast przyznać racje lub pozostać bez komentarza.

Jeśli dla Ciebie log to tylko kawałek tekstu (komunikat) to myślisz dokładnie tak, jak zwykły użytkownik nie mający pojęcia o mechanizmach jakimi zarządza, a nie jak programista; Dla mnie log to struktura danych zawierających kilka znaczących informacji o zdarzeniu jak: priorytet, czas utworzenia, komunikat + inne informacje nie przedstawione pytaczowi w tym wątku (choćby status zapoznania się z sygnalizowanym błędem czy status naprawienia problemu); Więc nie wmawiaj mi, że nie wiem o czym piszę, bo dokładnie to wiem i nie mam zamiaru przyznać racji komuś, kto nie myśli jak programista a jak szary użytkownik; Na dodatek tworzenie logów nie jest opatrzone sztywnym standardem, a posiada dość elastyczne zasady ich prowadzenia; O tym czym jest log i jakie jest jego przeznaczenie możesz przeczytać klikając na link; W tym artykule są jasno wyszczególnione elementy typowego logu, które są bardzo elastyczne:

Log (informatyka) napisał(a)

Typowy wpis w logu zawiera m.in. następujące informacje:

  • względny lub bezwzględny czas zdarzenia (np. data i godzina),
  • rodzaj zdarzenia, identyfikator (często wykorzystywany do rozdzielania informacji na kilka strumieni danych),
  • nazwa użytkownika, programu, procesu generującego wpis
  • dane o pobieranych plikach,
  • adres IP jeżeli operacja dotyczy komunikacji przez sieć,
  • kwalifikacja zdarzenia (poważny błąd, ostrzeżenie, raport z normalnego przebiegu prac, bardzo szczegółowy)
  • tekstowy opis zdarzenia
  • praktycznie każda informacja potrzebna administratorowi systemu, a możliwa do odczytania w sposób alfanumeryczny.

Więc log może zawierać dowolne informacje służące zarówno użytkownikowi, jak i programiście do zlokalizowania błędów i innych nieporządanych zachowań; Twierdzenie, że "log to jedynie komunikat" i pojęcie "modyfikacji logu" jest zmianą treści komunikatu jaki niesie jest bardzo dalekie od rzeczywistego pojęcia; Programista może zaprojektować system logowania tak jak chce, zawrzeć w logach takie informacje jak chce i jakie pomogą zarówno programiście w ulepszaniu programu i zlokalizowaniu przyczyn nieporządanych działań, jak i użytkownikowi w zrozumieniu awarii aplikacji;

Udawanie statusu przez log to moim zdaniem porażka systemu.

O czym Ty w ogóle piszesz? Jakie udawanie? Jeśli dla Ciebie modyfikacja pola logicznego (żeby się nie myliło - pola typu Boolean) w klasie logu to jakieś udawanie to na prawdę nie mamy o czym dyskutować;

Trzeba wiedzieć co i kiedy nadaje się do wstawienia jako log, albo do zaimplementowania jako status (zazwyczaj pokazywany w dolnej części aplikacji).

To co jest zazwyczaj robione często nie idzie w parze z tym, co chce się zaimplementować we własnym projekcie; Nikt nie musi małpować rozwiązań z innych aplikacji, więc nic nie stoi na przeszkodzie w modyfikowaniu logów (tak, logów - nie komunikatów, które są częścią logu);


Z Twoimi słowami @WinFormsApp1 zgodzę się tylko i wyłącznie w przypadku, gdy deklaracja typu logu będzie wyglądać tak:

type
  TLogInfo = type AnsiString;

a nie tak:

type
  TLogInfo = class(TObject)
  private
    FDateTime: TDateTime;
    FMessage: AnsiString;
  public
    constructor Create(const ADateTime: TDateTime; const AMessage: AnsiString);
    destructor Destroy(); override;
  public
    property DateTime: TDateTime read FDateTime;
    property Message: AnsiString read FMessage;
  public
    function GetLog(): AnsiString;
  end;
0

Pozwól, że uświadomię cię czym jest Wikipedia PL - otóż niczym więcej jak marną imitacją Wikipedii EN.
Skoro opierasz swoją wiedzę na polskiej edycji Wikipedii, to tylko pozostaje mi gratulować ci sukcesu.

Log (informatyka):

Typowy wpis w logu zawiera

Zabawne, popierasz swoją wiedzę złotymi myślami zwykłych użytkowników, a sam oskarżasz mnie, że myślę jak oni.
To jest zapewne realizacja tego, co napisane na wiki PL:

furious programming napisał(a):
type
  TLogInfo = type AnsiString;

**Czym jest log?**

Log to informacja o zdarzeniu zawarta w obiekcie opisującym go.

Skoro log to informacja o zdarzeniu, a zdarzenie (które kiedyś się wydarzyło) zmienić się nie może, to nie można modyfikować logu (dla ciebie - komunikatu) - a raczej nie powinno się.
Zmieniając pola obiektu, zazwyczaj nie zmieniasz logu, lecz sposób w jaki ten obiekt opisuje tą informację. Użytkownikowi pokazujesz obiekt, który zawiera treść logu.

furious programming napisał(a):
type
  TLogInfo = class(TObject)
  private
    FDateTime: TDateTime;
    FMessage: AnsiString;
  public
    constructor Create(const ADateTime: TDateTime; const AMessage: AnsiString);
    destructor Destroy(); override;
  public
    property DateTime: TDateTime read FDateTime;
    property Message: AnsiString read FMessage;
  public
    function GetLog(): AnsiString;
  end;

furious programming napisał(a):

Udawanie statusu przez log to moim zdaniem porażka systemu.

O czym Ty w ogóle piszesz? Jakie udawanie? Jeśli dla Ciebie modyfikacja pola logicznego (żeby się nie myliło - pola typu Boolean) w klasie logu to jakieś udawanie to na prawdę nie mamy o czym dyskutować;

To zdanie odnosiło się do:

furious programming napisał(a):

po co mógłbym je modyfikować? Choćby po to, by poinformować użytkownika o nowych-nieprzeczytanych logach

tak btw chcesz logiem (statusem na liście logów) informować o nieprzeczytanych logach? o.O


*Dla mnie modyfikacja loga to modyfikacja jego treści, zaś dla ciebie pól obiektu opisującego go. To zamieszanie wynika z naszych odmiennych definicji odnośnie loga. Dalsza dyskusja nie ma sensu.*
0

@tayamoto - może przedstaw jasno wszystkie funkcjonalności jakie powinien mieć Twój system logów, a wtedy dokładnie określi się co należy zaimplementować w klasie; Nie wspomniałeś o tym, że potrzebujesz wyświetlić logi np. posortowane według daty ich dodania, ale jeśli faktycznie to by się przydało, to można wykorzystać tylko jedną listę klasy TObjectList i zmodyfikować klasę TLogInfo, a raczej dodać do niej pole, w którym przechowywane będą informacje na temat priorytetu danego loga, np.:

Nie dodałem pytania na temat wszystkich opcji w systemie logów ponieważ staram się szanować Wasz czas wiec jeśli w miarę ogarniam sam to po co trolowac forum. A wiec:

  • system pewien sam zapisywać logi do pliku ini dla danego dnia. Jeśli nastąpi zmiana daty automatycznie tworzy nowy sektor w ini, czyści listboxa i zaczyna wstawiać nowe logi.
  • Po uruchomieniu programu następuje sprawdzenie czy w ini sa już logi z danego dnia jeśli tak wczytuje juz istniejące rekordy i zaczyna dodawać kolejne, jesli nie tworzy sektor.
    -Automatycznie kasuje wszystkie elementy ini w zadeklarowanych przez użytkownika interwalach czasowych tydzień, miesiąc, itd.
    -Umożliwia wczytanie z ini do listboxa wszystkich dni jako pojedynczych dat(bez logow) i po kliknięciu na dany dzień ładuje odpowiadające mu rekordy.
    -Umożliwia określenie przez użytkownika priorytetów zapisanych bądź ignorowanych do zapisu logów (czyli główne założenie tego tematu).

Oraz coś co możne uda sie dodać możliwość sortowania logów wg. rodzaju Komunikatu oraz ktorego z modułów programu dotyczy log. Sort powinien być realizowany w następujący sposób: jeśli użytkownik wybierze ze chce zobaczyć logi dotyczące np. bledow zostaną wczytane błędy, drugi np combo box powinien umożliwiać wysortowanie z załadowanych już bledow lokalizacje komunikatu. np moduł wysyłki @.

Sort podzielony na :
3 typy logów błędy, ostrzeżenia oraz informacje.
8 lokalizacji komunikatu.

Z tym ze sort to kwestia drugoplanowa.

0

Nie dodałem pytania na temat wszystkich opcji w systemie logów ponieważ staram się szanować Wasz czas wiec jeśli w miarę ogarniam sam to po co trolowac forum.

Tyle, że to są cenne informacje, dzięki którym nie trzeba się domyślać części funkjonalności; Zawsze można napisać wszystkie, ale podkreślić te, które umie się zrobić czy wie się mniej więcej;

  • system pewien sam zapisywać logi do pliku ini dla danego dnia. Jeśli nastąpi zmiana daty automatycznie tworzy nowy sektor w ini, czyści listboxa i zaczyna wstawiać nowe logi.

Więc potrzeba Ci metodę, która potrafi wczytywać i zapisywać logi do pliku INI; A czy strukturę tegoż pliku masz zaplanowaną, czy też potrzebujesz to skonsultować? Skoro dla jednego dnia logowania będzie jedna sekcja w pliku, to każdy log będzie musiał być zapisany w jednym wierszu w pliku; A skoro log będzie się składał z kilku informacji - musisz je oddzielić separatorem, by można było te informacje od siebie oddzielić podczas wyświetlania ich w kontrolce, np.:

[08.04.2013]
0=Moduł|Priorytet|Data|Komunikat
1=Moduł|Priorytet|Data|Komunikat
2=Moduł|Priorytet|Data|Komunikat

[09.04.2013]
0=Moduł|Priorytet|Data|Komunikat
1=Moduł|Priorytet|Data|Komunikat
2=Moduł|Priorytet|Data|Komunikat
3=Moduł|Priorytet|Data|Komunikat
4=Moduł|Priorytet|Data|Komunikat

i tak dalej; Dzięki separatorowi będzie można wydzielić poszczególne informacje po to, by łatwo je wyświetlić w osobnym stylu w kontrolce (inny styl dla modułu, inny dla priorytetu, inny dla daty, jeszcze inny dla komunikatu); Identyfikatory sekcji dla danego dnia mogą być inne, żeby można było je łatwo porównać z obecną datą;

  • Po uruchomieniu programu następuje sprawdzenie czy w ini sa już logi z danego dnia jeśli tak wczytuje juz istniejące rekordy i zaczyna dodawać kolejne, jesli nie tworzy sektor.

Więc po uruchomieniu musisz sprawdzić, czy sekcja o identyfikatorze takim, jaka jest przekonwertowana data istnieje czy nie; Obsługę plików INI pewnie znasz, więc nie będę wypisywał metod potrzebnych zarówno do wykonania sprawdzenia istnienia sekcji, jak również wczytania jej zawartości;

-Automatycznie kasuje wszystkie elementy ini w zadeklarowanych przez użytkownika interwalach czasowych tydzień, miesiąc, itd.

Więc możesz załadować listę samych identyfikatorów wszystkich sekcji i w pętli sprawdzasz czy mieszczą się w przedziale, czy nie; Jeśli nie mieszczą się (są za stare) - usuwasz całą sekcję;

-Umożliwia wczytanie z ini do listboxa wszystkich dni jako pojedynczych dat(bez logow) i po kliknięciu na dany dzień ładuje odpowiadające mu rekordy.

To samo co wyżej - pobierasz listę samych identyfikatorów sekcji; Użytkownik po wybraniu danej pozycji wskaże tym samym nazwę sekcji, z której odbędzie się wczytywanie logów;

-Umożliwia określenie przez użytkownika priorytetów zapisanych bądź ignorowanych do zapisu logów (czyli główne założenie tego tematu).

Czyli podczas ładowania logów do kontrolki sprawdzasz czy spełniają zadane kryteria i jeśli tak - dodajesz do kontrolki, jeśli nie - pomijasz i sprawdzasz dalej;

Oraz coś co możne uda sie dodać możliwość sortowania logów wg. rodzaju Komunikatu oraz ktorego z modułów programu dotyczy log.

No widzisz, teraz doszła dodatkowa informacja do klasy logu jak moduł wysyłający komunikat;

Sort powinien być realizowany w następujący sposób: jeśli użytkownik wybierze ze chce zobaczyć logi dotyczące np. bledow zostaną wczytane błędy

To nie jest sortowanie (które dotyczy ułożenia elementów w liście), tylko filtrowanie (które dotyczy wybrania odpowiednich elementów, a odrzucenie tych, które nie spełniają wymogów);

drugi np combo box powinien umożliwiać wysortowanie z załadowanych już bledow lokalizacje komunikatu. np moduł wysyłki @.

To już jest sortowanie; Tylko że nie napisałeś jak oznaczasz poszczególne moduły; Najprościej to przydzielić im identyfikatory liczbowe, które przechowywane będą w polu logu, a podczas wyświetlania ich w kontrolce będą konwertowane do postaci zrozumiałej; Np. "moduł wysyłki" będzie miał identyfikator 1, ale w kontrolce wyświetlisz pełną nazwę Moduł wysyłki pobraną z macierzy identyfikatorów; W ten sposób sortowanie będzie można przeprowadzić sprawnie i bez zbędnego kombinowania, a w zdarzeniu rysującym odpowiednią pozycję w TListBox według indeksu modułu pobierzesz i narysujesz pełną jego nazwę z macierzy;

Z tym ze sort to kwestia drugoplanowa.

Skoro już myślisz o sortowaniu - zaimplementuj od razu.


EDIT: A nie zastanawiałeś się nad innym typem pliku do tego typu rzeczy, niż INI?

0

Ale wszystkie rzeczy poza priorytetami i sortowaniem już mam. Realizują je poniższe procedury. Teraz zostały priorytety i sortowanie jakieś sugestie jak to dodać do istniejącego kodu.

Btw. Mam nadzieje ze nie narobiłem za dużo baboli.

 DayLogs:String;
  B:TDateTime;
  OstatnieKasowanie:TDateTime;
  datakasowania:TDateTime;

procedure TUstawienia.FormCreate(Sender: TObject);
begin
   DayLogs:=(DateToStr(date));
   WczytajWybranyDzien;
   B:=now; //Ustawienie Aktalnel Daty dla Logow
   LLogProgress.OnClick:=Nil;
   ComboBox1.OnChange(ComboBox1.Items);
end;
////-Procedry przeniesienia logow do okna-\\\\\\\\\\\
procedure TUstawienia.Log(const Msg: String);
var
  A: TDateTime;
  Result : Boolean;
begin
  A := Now;
  Result := SameDate(A,B);

  if not Result then
       begin
          LLogProgress.Items.Clear;
          B := A;
       end;

  if not Assigned(LLogProgress) then
    Exit;
    LLogProgress.Items.Insert(0,(dateToStr(date))+'. '+(TimeToStr(time))+'. '+Msg);
    LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
    ZapiszLogi;
    If date = datakasowania then UsunZIni;
end;

procedure TUstawienia.Log(const Msg: String; const Args: array of const);
begin
  Log(format(Msg, Args));
end;
////////-Procedra Zapisu logow do pliku INI-\\\\\\\\\\\\
procedure TUstawienia.ZapiszLogi;
var
  ini: TIniFile;
  i:integer;
begin
  ini:= TIniFile.Create(ExtractFilePath(Application.ExeName)+'Pliki Ustawien\Logi.ini');
  try
  for i:=0 to LLogProgress.Items.Count - 1 do
    ini.WriteString(DateToStr(date), IntToStr(i), LLogProgress.Items[i]);
  finally
    ini.Free;
  end;
end;

procedure TUstawienia.Button9Click(Sender: TObject);
begin
  ZapiszLogi;
end;

Procedure TUstawienia.UsunZIni;
begin
     LLogProgress.Items.Clear;
     TFileStream.Create('Pliki Ustawien\Logi.ini',fmCreate).Free;
     Log('Rejestr zostal wykasowany');
     OstatnieKasowanie:=date;
end;
 /////////-Procedura wczytywania Logow z Aktalnego dnia-\\\\\\\\\\\\\\\\\\\\\

Procedure TUstawienia.WczytajWybranyDzien;
var
  ini: TIniFile;
  s: string;
  Dateindex: integer;
begin
  LLogProgress.Items.Clear;
  ini:= TIniFile.Create(ExtractFilePath(Application.ExeName)+'Pliki Ustawien\Logi.ini');
  try
  Dateindex:= 0;
  while True do
  begin
    s:= ini.ReadString(DayLogs, IntToStr(Dateindex), '');
    if s = '' then
         break;
    LLogProgress.Items.Add(s);
    Inc(Dateindex);
  end;
  finally
    ini.Free;
end;
end;

procedure TUstawienia.Button13Click(Sender: TObject);
var
  ini: TIniFile;
begin
    ini:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'Pliki Ustawien\Logi.ini');
    INI.ReadSections(LLogProgress.Items);
    ini.Free;
    LLogProgress.OnClick:=LLogProgressClick;
end;

procedure TUstawienia.LLogProgressClick(Sender: TObject);
begin
  DayLogs:=(LLogProgress.items.strings[LLogProgress.itemindex]);
  WczytajWybranyDzien;
  LLogProgress.OnClick:=Nil;
end;

procedure TUstawienia.ComboBox1Change(Sender: TObject);
begin
case ComboBox1.ItemIndex of
    0:datakasowania:=(Incday(OstatnieKasowanie,0));
    1:datakasowania:=(Incday(OstatnieKasowanie,7));
    2:datakasowania:=(Incday(OstatnieKasowanie,30));
    3:datakasowania:=(Incday(OstatnieKasowanie,90));
    4:datakasowania:=(Incday(OstatnieKasowanie,180));
    5:datakasowania:=(Incday(OstatnieKasowanie,365));
end;
  Label2.Caption:= ('Data nastepnego autokasowana Logow '+DateToStr(datakasowania));
end;
0
Procedure TUstawienia.WczytajWybranyDzien;
var
  ini: TIniFile;
  s: string;
  Dateindex: integer;
begin
  LLogProgress.Items.Clear;
  ini:= TIniFile.Create(ExtractFilePath(Application.ExeName)+'Pliki Ustawien\Logi.ini');
  try
  Dateindex:= 0;
  while True do
  begin
    s:= ini.ReadString(DayLogs, IntToStr(Dateindex), '');
    if s = '' then
         break;
    LLogProgress.Items.Add(s);
    Inc(Dateindex);
  end;
  finally
    ini.Free;
end;
end;

W klasie TINIFile jest taka metoda jak:

procedure TINIFile.ReadSection(const Section: String; Strings: TStrings);

która wczytuje wszystkie klucze danej sekcji - zainteresuj się nią;


procedure TUstawienia.ComboBox1Change(Sender: TObject);
begin
case ComboBox1.ItemIndex of
    0:datakasowania:=(Incday(OstatnieKasowanie,0));
    1:datakasowania:=(Incday(OstatnieKasowanie,7));
    2:datakasowania:=(Incday(OstatnieKasowanie,30));
    3:datakasowania:=(Incday(OstatnieKasowanie,90));
    4:datakasowania:=(Incday(OstatnieKasowanie,180));
    5:datakasowania:=(Incday(OstatnieKasowanie,365));
end;
  Label2.Caption:= ('Data nastepnego autokasowana Logow '+DateToStr(datakasowania));
end;

Można prościej z wykorzystaniem macierzy z liczbami dni:

procedure TUstawienia.ComboBox1Change(Sender: TObject);
const
  INC_DAY_VAL_ARR: array [0 .. 5] of Word = (0, 7, 30, 90, 180, 365);
begin
  DataKasowania := IncDay(OstatnieKasowanie, INC_DAY_VAL_ARR[ComboBox1.ItemIndex]);
  Label2.Caption:= ('Data nastepnego autokasowana Logow ' + DateToStr(DataKasowania));
end;

Ogólnie to coś jest na rzeczy, ale całość wypada opakować w klasę.

0

Jak tylko uda mi sie odpalić cały mechanizm opakuje to w jakaś sensowna klasę. Ok udało mi sie zmienić procedury dodawania logów- poszerzyć o dodatkowy parametr typu integer, określający wagę wiadomości. Ustaliłem również zmienna wybierana z comboboxa która warunkuje dodawanie lub ignorowanie komunikatów, teraz pozostaje jedynie zmodyfikować procedurę dodawania komunikatów w zależności od wyboru comboboxa oraz integera określonego w samym, wywołaniu komunikatu, proszę o jakieś sugestie, bo pomysłów brak. Tak w chwili obecnej wyglądają procedury:

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin

  if not Assigned(LLogProgress) then
    Exit;
    LLogProgress.Items.Insert(0,(TimeToStr(time)+'. '+Msg));
    LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
end;

procedure TUstawienia.Log(const Msg: String; const Args: array of const; prior:integer);
begin
  Log(format(Msg, Args),prior);
end;

A tak wygląda wywołanie:

Log('Komunikat',0);
0

Ustaliłem również zmienna wybierana z comboboxa która warunkuje dodawanie lub ignorowanie komunikatów,

Co to znaczy "warunkuje dodawanie lub ignorowanie komunikatów"? Bo mi to brzmi tak, jakby ten ComboBox ustalał które komunikaty mają być wpisane do listy, a które nie; Czyli jak wybierze się np. błędy, to zarówno informacje jak i ostrzeżenia w ogóle nie będą logowane i nie będą lądować na liście logów;

Z drugiej strony jednak domyślam się, że Tobie chodzi o filtrowanie logów, a nie o wybieranie które zdarzenia mają być logowane; Jeśli według tego ComboBox faktycznie ma się filtrować logi, to napisałem Ci wcześniej jak należy to wykonać - w procedurze ładującej logi do kontrolki ListBox sprawdzasz w pętli każdy log pod kątem priorytetu i jeśli ma być wyświetlony - dodajesz go do kontrolki, jeśli nie - pomijasz go i sprawdzasz następny;

U Ciebie to jednak wygląda tak, że nie masz żadnej listy ze zbiorem logów, a z podanych metod TUstawienia.Log wynika, że wszystkie nowe logi lądują bezpośrednio do kontrolki ListBox; To zmienia całkowicie postać rzeczy, bo z ten sposób nie można wykonać filtrowania logów, bo usuwając je z kontrolki straci się do nich referencję, a tym samym usunie się je bezpowrotnie; Dlatego od początku tego wątku sugeruję Ci stworzenie klasy silnika logowania z listą wszystkich logów; Dzięki temu wszystkie logi będą na liście w silniku, a kontrolkę wykorzystasz jedynie do ich wyświetlenia tak, jak Pan Bóg przykazał; Wtedy filtrowanie logów pod kątem priorytetu okaże się bajecznie proste - klasa silnika logów powinna posiadać metodę, która w argumentach pobierze kryteria wyświetlania, a kod ładujący logi do kontrolki będzie mógł wybrać tylko te, które spełniają dane kryteria; Wtedy filtrowaniem nie pousuwasz sobie logów, a jedynie wyświetlisz te, które interesują Cię w danym momencie;

Ogólnie to kontrolki zawierające listy, jak: ListBox, CheckListBox, ListView, ComboBox itd. nie służą do gromadzenia i przechowywania informacji, a do ich wyświetlania, więc nie możesz swojego mechanizmu logowania oprzeć jedynie na pakowaniu nowych komunikatów do kontrolki i nic więcej; Poza tym, jeśli stworzysz sobie klasę silnika logowania unikniesz zbędnego kombinowania, które teraz Cię przerosło;

W pierwszym przykładowym programie jaki podałem z początku wątku miałeś przedstawioną przykładową klasę, w której każdy log był klasą zawierającą kilka informacji na temat pojedynczego logu; Dzięki temu można było łatwo odczytać poszczególne informacje, jak: priorytet, datę czy komunikat, bo były to osobne pola klasy; Dodana była także metoda, która wszystkie informacje na temat logu zamieniała na jeden ciąg znaków, który służył jedynie do wyświetlenia w kontrolce; Dzięki temu, że trzy informacje o logu były przechowywane w osobnych polach, można było łatwo przeszukać listę logów pod kątem dowolnych kryteriów - chciałem według priorytetu - wystarczyło sprawdzić pole FPriority, chciałem według daty - trzeba było sprawdzić pole FDateTime; Jeśli wszystkie informacje na temat jednego logu będą od razu połączone przez konwersję do łańcuchów i ich konkatenację, to wiesz ile trzeba wykonać dodatkowych operacji, by je z powrotem wyłuskać i sprawdzić? A w Twoim przypadku będzie to konieczne, bo u Ciebie Log jest łańcuchem znaków, a nie klasą czy strukturą danych;

Podsumowując - aby uniknąć problemów i zbędnego kombinowania musisz stworzyć osobną klasę obsługującą cały proceder logowania; Jeśli dalej nie będziesz chciał skorzystać z klasy, to bez kombinowania jak koń pod górę filtrowanie będzie po prostu awykonalne;


EDIT:

  1. Dlaczego masz w klasie formularza zadeklarowane dwie metody o takim samym identyfikatorze TUstawienia.Log? Domyślam się, że poprawnie je przeładowujesz, ale w jakim to celu?
  2. Czemu dodając nowy log do kontrolki wstawiasz go w indeksie 0 (czyli na wizualną samą górę listy), a przypisujesz ItemIndex ostatniego? Chyba nie muszę tłumaczyć co się stanie, jeśli lista logów jest kilkakrotnie dłuższa niż może pomieścić jeden "ekran" kontrolki;

EDIT 2:

tayamoto napisał(a)

Jak tylko uda mi sie odpalić cały mechanizm opakuje to w jakaś sensowna klasę.

Nie czekaj z tym bo to, co uda Ci się wykombinować bez dodatkowej klasy będzie zupełnie inne, niżeli ją wykorzystasz.

0
furious programming napisał(a):

Ustaliłem również zmienna wybierana z comboboxa która warunkuje dodawanie lub ignorowanie komunikatów,

Co to znaczy "warunkuje dodawanie lub ignorowanie komunikatów"? Bo mi to brzmi tak, jakby ten ComboBox ustalał które komunikaty mają być wpisane do listy, a które nie; Czyli jak wybierze się np. błędy, to zarówno informacje jak i ostrzeżenia w ogóle nie będą logowane i nie będą lądować na liście logów;
</quote>

Właśnie o to chodzi by combobox ustalał które logi maja byc ładowane do listy logów kryteria comboboxa nie beda zawierały rekordu np. "bledy" a wagę komunikatu, deklarowana przez użytkownika wszystkie, ważne, bardzo ważne. Natomiast dopiero z tych komunikatów ustalę kryteria sortu np. rodzaj komunikatu czyli informacja ostrzeżenie i błąd oraz moduł z którego pochodzą, np. wysyłka @. Rozwiązanie takie chce zastosować ponieważ tak jak pisałem będzie kilkaset wywołań logów wiele o niski znaczeniu i potrzebuje w sposób szybki zmieniać kryteria dodawania a nie sortowania logów.

Ale juz wszystko ogarnięte, oczywiście rozwiązanie okazało sie banalne.

Zmiana opcji dodawania w comboboxie:

Priorytet: integer;

procedure TUstawienia.ComboBox2Change(Sender: TObject);
const
  Zmiana_Logow: array [0 .. 3] of Word = (0, 1, 2, 3);
begin
  Priorytet := ( Zmiana_Logow[ComboBox2.ItemIndex]);
end;

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin
 if prior >= priorytet then
 begin
  if not Assigned(LLogProgress) then
    Exit;
    LLogProgress.Items.Insert(0,(TimeToStr(time)+'. '+Msg));
    LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
  end;
end;
0

Właśnie o to chodzi by combobox ustalał które logi maja byc ładowane do listy logów

Tyle, że jeśli nie posiadasz żadnego obiektu, w którym zbierane są wszystkie logi (a tak teraz jest) - nie możesz zobaczyć co było logowane wcześniej, bo logi te zostały odrzucone (niezapisane); Dlatego od początku tego wątku przyciskam Cię żebyś stworzył klasę, która będzie przechowywać wszystkie logi; Teraz, jeśli wybierzesz logi o wadze 0 (czyli najważniejsze) - program odrzuci wszystkie inne o wadze mniejszej niż 0 i jeśli przełączysz w ComboBox żeby pokazywał Ci logi wszystkich wag - poprzednie nie będą istnieć; Załóżmy, że:

  • wybierasz w ComboBox wagę 0,

  • logowanie zdarzeń o tej wadze rozpoczyna się o np. 12:00 i logi zbierane są przez 15 minut,

  • o 12:15 wybierasz w ComboBox opcję, która zezwala na zbieranie logów z wszystkich wag,

  • wszystkie logi o wadze innej, niż 0 w przedziale czasowym 12:00 .. 12:15 nie zostały zapisane, więc nie możesz już sprawdzić jakie mniej ważne informacje logowała aplikacja;
    Cały czas chodzi mi właśnie o taką sytuację - ma ona miejsce teraz w obecnym kodzie; A teraz rozwiązanie z wykorzystaniem dodatkowej klasy:

  • wybierasz w ComboBox wagę 0,

  • logowanie zdarzeń o tej wadze rozpoczyna sie o 12:00 i logi zbierane są przez 15 minut - podobnie jak wcześniej,

  • program cały czas zbiera logi wszystkich wag i zapisuje je do listy w obiekcie silnika logowania,

  • obiekt silnika po dodaniu nowego logu sprawdza, czy jego waga spełnia kryteria wyświetlania w kontrolce według wartości w ComboBox i jeśli spełnia - nowy log zostaje dodany do kontrolki,

  • o 12:15 wybierasz w ComboBox opcję, która zezwala na wyświetlanie wszystkich logów o dowolnej wadze,

  • wszystkie logi o dowolnej wadze z przedziału czasowego 12:00 .. 12:15 istnieją na liście w silniku, więc można je wszystkie załadować do kontrolki, przez co żaden log nie został utracony;
    Jak widzisz w Twoim obecnym kodzie logi są tracone, a w zaproponowanym przeze mnie nie, dlatego że zapisywane są wszystkie (czyli gromadzenie logów odbywa się na niejawnej liście w obiekcie silnika), a wyświetlane są w kontrolce (bo do tego służą kontrolki z listami) tylko wybrane;

Do czego zmierzam - jeśli nie chcesz zapisywać logów nie spełniających kryteriów ustalonych w ComboBox, to dlaczego wcześniej o tym nie wspomniałeś? Ja wcześniej domyślałem się, że Tobie chodzi o filtrowanie logów mając ich pełną listę, a nie o bezpowrotne odrzucanie części z nich; Jeśli faktycznie o to Ci chodzi, to cały problem można rozwiązać jedyn warunkiem sprawdzającym, czy waga dodawanego logu jest poprawna względem wartości w ComboBox i to wszystko;

kryteria comboboxa nie beda zawierały rekordu np. "bledy" a wagę komunikatu, deklarowana przez użytkownika wszystkie, ważne, bardzo ważne.

No dobrze, to i tak na jedno wychodzi z tym, co podałem Ci wcześniej; Jednak założenie masz jedno, a kod realizuje drugie; Ten warunek:

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin
 if prior >= priorytet then

błędnie określa czy log ma zostać dodany do listy, czy nie; Bo jeżeli będziesz chciał dodawać logi o wadze 0, to i tak dodane zostaną o wadze 1 i 2 - dlatego w tym warunku musisz sprawdzić czy prior = priorytet i jeśli tak - dodać log;

Tak nawiasem - wykorzystujesz zmienną priorytet, która jest zbędna bo możesz zrezygnować zarówno z niej, jak i ze zdarzenia ComboBox2Change, bo możesz porównać wagę nowego logu bezpośrednio z wartością z ComboBox2:

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin
  if prior = ComboBox2.ItemIndex then
    if not Assigned(LLogProgress) then
      Exit;

  LLogProgress.Items.Insert(0, (TimeToStr(time) + '. ' + Msg));
  LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
end;

Jednak takie porównanie wagi nowego logu z wartością z ComboBox także jest błędne, bo nie pozwala na dodawanie wszystkich logów o dowolnej wadze - dlatego zasugerowałem Ci wykorzystanie macierzy z dopuszczanymi w chwili obecnej wagami; To lub podobne rozwiązanie musisz wykorzystać, by poprawnie zrealizować założenia;

Tak nawiasem: słowo prior znaczy wcześniejszy, co nijak ma się do priorytetu czy wagi.

0
  • wybierasz w ComboBox wagę 0,

  • logowanie zdarzeń o tej wadze rozpoczyna się o np. 12:00 i logi zbierane są przez 15 minut,

  • o 12:15 wybierasz w ComboBox opcję, która zezwala na zbieranie logów z wszystkich wag,

  • wszystkie logi o wadze innej, niż 0 w przedziale czasowym 12:00 .. 12:15 nie zostały zapisane, więc nie możesz już sprawdzić jakie mniej ważne informacje logowała aplikacja;
    Cały czas chodzi mi właśnie o taką sytuację - ma ona miejsce teraz w obecnym kodzie; A teraz rozwiązanie z wykorzystaniem dodatkowej klasy:

  • wybierasz w ComboBox wagę 0,

  • logowanie zdarzeń o tej wadze rozpoczyna sie o 12:00 i logi zbierane są przez 15 minut - podobnie jak wcześniej,

  • program cały czas zbiera logi wszystkich wag i zapisuje je do listy w obiekcie silnika logowania,

  • obiekt silnika po dodaniu nowego logu sprawdza, czy jego waga spełnia kryteria wyświetlania w kontrolce według wartości w ComboBox i jeśli spełnia - nowy log zostaje dodany do kontrolki,

  • o 12:15 wybierasz w ComboBox opcję, która zezwala na wyświetlanie wszystkich logów o dowolnej wadze,

  • wszystkie logi o dowolnej wadze z przedziału czasowego 12:00 .. 12:15 istnieją na liście w silniku, więc można je wszystkie załadować do kontrolki, przez co żaden log nie został utracony;
    Jak widzisz w Twoim obecnym kodzie logi są tracone, a w zaproponowanym przeze mnie nie, dlatego że zapisywane są wszystkie (czyli gromadzenie logów odbywa się na niejawnej liście w obiekcie silnika), a wyświetlane są w kontrolce (bo do tego służą kontrolki z listami) tylko wybrane;

Zgadza sie zdaje sobie sprawę ze po wybraniu wagi 2 większość komunikatów nie będzie zapisanych. Jednak większość będzie bardzo szczegółowych np. sama wysyłka @ to około 8 komunikatów, bądź 1 jeśli wybiorę wagę 2. Wiem ze opisywana przez Ciebie klasa zapisuje wszystkie komunikaty a potem je filtruje w oparciu o znaczniki, jednak do moich potrzeb wystarczy ignorowanie lub nie komunikatów, tak to sobie wymarzyłem :). Natomiast sam sort to już inna kwestia.

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin
 if prior >= priorytet then

błędnie określa czy log ma zostać dodany do listy, czy nie; Bo jeżeli będziesz chciał dodawać logi o wadze 0, to i tak dodane zostaną o wadze 1 i 2 - dlatego w tym warunku musisz sprawdzić czy prior = priorytet i jeśli tak - dodać log;

Tak nawiasem - wykorzystujesz zmienną priorytet, która jest zbędna bo możesz zrezygnować zarówno z niej, jak i ze zdarzenia ComboBox2Change, bo możesz porównać wagę nowego logu bezpośrednio z wartością z ComboBox2:

procedure TUstawienia.Log(const Msg: String; prior:integer);
begin
  if prior = ComboBox2.ItemIndex then
    if not Assigned(LLogProgress) then
      Exit;

  LLogProgress.Items.Insert(0, (TimeToStr(time) + '. ' + Msg));
  LLogProgress.ItemIndex := LLogProgress.Items.Count - 1;
end;

Jednak takie porównanie wagi nowego logu z wartością z ComboBox także jest błędne, bo nie pozwala na dodawanie wszystkich logów o dowolnej wadze - dlatego zasugerowałem Ci wykorzystanie macierzy z dopuszczanymi w chwili obecnej wagami; To lub podobne rozwiązanie musisz wykorzystać, by poprawnie zrealizować założenia;

Celowo taki właśnie warunek określiłem:

if prior >= priorytet then

Mianowicie waga "0" odpowiada pozycji coboboxa "dodawaj" wszystkie komunikaty" a wiec "0""1""2", waga 1 pozycji dodawaj ważne komunikaty a wiec "1""2". Natomiast waga 2 pozycji dodawaj najważniejsze komunikaty a wiec tylko "2". Co do zmiennej "priorytet" oraz indeksowanie komunikatów to faktycznie wtopa.

1

Mianowicie waga "0" odpowiada pozycji coboboxa "dodawaj" wszystkie komunikaty" a wiec "0""1""2", waga 1 pozycji dodawaj ważne komunikaty a wiec "1""2". Natomiast waga 2 pozycji dodawaj najważniejsze komunikaty a wiec tylko "2".

Po słowiach "dodawaj ważne komunikaty" spodziewałem się jedynie tych ważnych, nie wliczając mało ważnych i bardzo ważnych; Dlatego zwróciłem Ci uwagę na ten warunek :]

Co do zmiennej "priorytet" oraz indeksowanie komunikatów to faktycznie wtopa.

Nie rozumiem, przecież w Twoim kodzie za priorytet logu odpowiada jego waga (0, 1 i 2) - to stanowi o ich ważności i na podstawie właśnie wagi odbywa się filtrowanie;

A co do całego procesu logowania - z kodu, jaki do tej pory wklejałeś wynika, że to nie jest "standardowy" system logowania, bo który program trzymałby okienko z listą komunikatów na wierzchu denerwując przez to użytkownika? Nie wiem czy traktujesz te logi i listę jako narzędzie do własnego procesu debugowania czy coś innego, ale tak to wygląda, bo logi nie są nigdzie przechowywane tylko cały czas lądują do widocznej na ekranie kontrolki;

Więc widzę, że poradziłeś sobie z filtrowaniem logów, ale dalej wątek jest otwarty (nie zaznaczyłeś posta rozwiązującego problem) stąd nie wiem, czy zapomniałeś odfajkować danego posta, czy jeszcze masz jakieś pytania; Napisz czego jeszcze nie wiesz.

0

A co do całego procesu logowania - z kodu, jaki do tej pory wklejałeś wynika, że to nie jest "standardowy" system logowania, bo który program trzymałby okienko z listą komunikatów na wierzchu denerwując przez to użytkownika? Nie wiem czy traktujesz te logi i listę jako narzędzie do własnego procesu debugowania czy coś innego, ale tak to wygląda, bo logi nie są nigdzie przechowywane tylko cały czas lądują do widocznej na ekranie kontrolki;

Więc widzę, że poradziłeś sobie z filtrowaniem logów, ale dalej wątek jest otwarty (nie zaznaczyłeś posta rozwiązującego problem) stąd nie wiem, czy zapomniałeś odfajkować danego posta, czy jeszcze masz jakieś pytania; Napisz czego jeszcze nie wiesz.

Faktycznie założenia sa nieco niestandardowe. Natomiast same komunikaty przechowywane sa w ini i takie rozwiązanie mi wystarczy. Na ta chwile nie mam więcej pytań dziękuje za zainteresowanie i Twoja klasę na pewno sie przyda.

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