Simples Logsystem [Include]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Simples Logsystem [Include]

Beitrag von cxAlex »

Servus.
Ich hab mir ein kleines Logsystem gebastelt das in das nächste Release von Simple Container eingebaut wird.

Das System ist einfach, kann beliebig viele Log - Prioritäten verwalten (vordefiniert: Info, Warning, Error) und diese auch einfach wiedergeben. Zudem lässt es sich bequem an/ausschalten, ich finde das einfach komfortabler beim Einbau in andere Projekte.

Einfach mal ausprobieren, ich denke das ganze ist selbsterklärend und gut dokumentiert:

Bugs, Kommentare, Wünsche, ... einfach hier posten :D

Logger.pbi:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Einfaches Logsystem
; Author: Alexander Aigner
; PB 4.4+ x86/x64 Ascii/Unicode
; ------------------------------------------------------------------------------------

XIncludeFile "LinkedList.pbi"

; EnableExplicit

Structure Logger_Entry
  Priority.l
  Time.l
  *Message
EndStructure

Structure Logger_Data
  LogList.i
  MinViewPriority.l
  *Current.Logger_Entry
  Enable.a
EndStructure

Enumeration
  #Logger_Info
  #Logger_Warning
  #Logger_Error
EndEnumeration

; ------------------------------------------------------------------------------------
;  Erstellt einen neuen Logger
;
;  Rückgabe: Logger - Handle
; ------------------------------------------------------------------------------------
Procedure Logger_New()
  Protected *Logger.Logger_Data = AllocateMemory(SizeOf(Logger_Data))
  
  With *Logger
    \LogList = LL_New()  
    \Enable = #True
  EndWith
  
  ProcedureReturn *Logger  
EndProcedure


; ------------------------------------------------------------------------------------
;  Löscht alle Einträge im Logger
;  *Logger: Logger Handle
;
;  Rückgabe: 0
; ------------------------------------------------------------------------------------
Procedure Logger_Clear(*Logger.Logger_Data)
  Protected *LogEntry.Logger_Entry
  
  With *Logger
    LL_Reset(\LogList)
    While LL_Next(\LogList)
      *LogEntry = LL_Get(\LogList)
      LL_Delete(\LogList)
      FreeMemory(*LogEntry\Message)
      FreeMemory(*LogEntry)
    Wend
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Gibt den Logger frei
;  *Logger: Logger Handle
;
;  Rückgabe: 0
; ------------------------------------------------------------------------------------
Procedure Logger_Free(*Logger.Logger_Data)
  
  With *Logger
    Logger_Clear(*Logger)
    LL_Free(\LogList)
    FreeMemory(*Logger)
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Aktiviert/Deaktiviert den Logger
;  *Logger: Logger Handle
;  Enable: #False: Logger ist deaktiviert, sonst aktiviert
;
;  Rückgabe: 0
; ------------------------------------------------------------------------------------
Procedure Logger_Enable(*Logger.Logger_Data, Enable = #True)
  
  With *Logger
    \Enable = Enable 
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Erstellt einen neuen Eintrag im Logger
;  *Logger: Logger Handle
;  Eintrag: Log - Nachricht
;  Priority: Priorität des Eintrags
;
;  Rückgabe: 0
; ------------------------------------------------------------------------------------
Procedure Logger_Log(*Logger.Logger_Data, Message$, Priority = #Logger_Info)
  Protected *LogEntry.Logger_Entry
  
  With *Logger
    If Message$ And \Enable
      LL_Last(\LogList)
      
      *LogEntry = AllocateMemory(SizeOf(Logger_Entry))
      *LogEntry\Time = Date()
      *LogEntry\Priority = Priority
      *LogEntry\Message = AllocateMemory(StringByteLength(Message$) + SizeOf(Character))
      PokeS(*LogEntry\Message, Message$)
      
      LL_Add(\LogList)
      LL_Set(\LogList, *LogEntry)
    EndIf 
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Startet eine Auflistung aller Einträge im Logger
;  *Logger: Logger Handle
;  MinimumViewPriority: Minimale Priorität der Einträge die aufgelistet werden sollen
;
;  Rückgabe: 0
; ------------------------------------------------------------------------------------
Procedure Logger_StartView(*Logger.Logger_Data, MinimumViewPriority = #Logger_Info)
  
  With *Logger
    LL_Reset(\LogList)
    \MinViewPriority = MinimumViewPriority
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Läd den nächsten Eintrag aus dem Logger
;  *Logger: Logger Handle
;
;  Rückgabe: #True wenn Eintrag vorhanden, sonst #False
; ------------------------------------------------------------------------------------
Procedure Logger_ViewNext(*Logger.Logger_Data)
  Protected RtVar, *LogEntry.Logger_Entry
  
  With *Logger
    \Current = #Null
    
    While LL_Next(\LogList)
      *LogEntry = LL_Get(\LogList)
      If *LogEntry\Priority >= \MinViewPriority
        \Current = *LogEntry
        RtVar = #True
        Break
      EndIf
    Wend
  EndWith
  
  ProcedureReturn RtVar
EndProcedure

; ------------------------------------------------------------------------------------
;  Läd die Zeit des aktuellen Eintrags
;  *Logger: Logger Handle
;
;  Rückgabe: Zeit
; ------------------------------------------------------------------------------------
Procedure Logger_GetTime(*Logger.Logger_Data)
  
  With *Logger
    If \Current
      ProcedureReturn \Current\Time  
    EndIf
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Läd die Priorität des aktuellen Eintrags
;  *Logger: Logger Handle
;
;  Rückgabe: Priorität
; ------------------------------------------------------------------------------------
Procedure Logger_GetPriority(*Logger.Logger_Data)
  
  With *Logger
    If \Current
      ProcedureReturn \Current\Priority 
    EndIf
  EndWith
EndProcedure

; ------------------------------------------------------------------------------------
;  Läd die Nachricht des aktuellen Eintrags
;  *Logger: Logger Handle
;
;  Rückgabe: Nachricht
; ------------------------------------------------------------------------------------
Procedure.s Logger_GetMessage(*Logger.Logger_Data)
  
  With *Logger
    If \Current
      ProcedureReturn PeekS(\Current\Message)
    EndIf
  EndWith
EndProcedure
LinkedList.pbi:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; LinkedList
; Simple Linked List
; ------------------------------------------------------------------------------------

; ------------------------------------------------------------------------------------
; Strukturen
; ------------------------------------------------------------------------------------

Structure LL_Data
  *Prev.LL_Data
  *Next.LL_Data
  *Data
EndStructure

Structure LL_Header
  *Cur.LL_Data
  *First.LL_Data
  *Last.LL_Data
  Count.i
EndStructure

; ------------------------------------------------------------------------------------
;- Erstellen, Hinzufügen, Löschen
; ------------------------------------------------------------------------------------

Procedure LL_New()
  Protected *cLL.LL_Header = AllocateMemory(SizeOf(LL_Header))
  ProcedureReturn *cLL
EndProcedure

Procedure LL_Add(*LL.LL_Header)
  Protected *nLL.LL_Data = AllocateMemory(SizeOf(LL_Data))
  If Not *LL\Cur
    If *LL\First
      *LL\Cur = *LL\First
    ElseIf *LL\Last
      *LL\Cur = *LL\Last
    EndIf
  EndIf
  If *LL\Cur
    If *LL\Cur\Next
      *LL\Cur\Next\Prev = *nLL
      *nLL\Next = *LL\Cur\Next
    EndIf
    *LL\Cur\Next = *nLL
  EndIf
  *nLL\Prev = *LL\Cur
  If *LL\Cur = *LL\Last
    *LL\Last = *nLL
  EndIf
  If Not *LL\First
    *LL\First = *nLL
  EndIf
  *LL\Cur = *nLL
  *LL\Count + 1
EndProcedure

Procedure LL_Delete(*LL.LL_Header)
  Protected *cLL.LL_Header
  If *LL\Cur
    If *LL\Cur\Prev
      *LL\Cur\Prev\Next = *LL\Cur\Next
    EndIf
    If *LL\Cur\Next
      *LL\Cur\Next\Prev = *LL\Cur\Prev
    EndIf
    If *LL\Cur = *LL\Last
      *LL\Last = *LL\Cur\Prev
    EndIf
    If *LL\Cur = *LL\First
      *LL\First = *LL\Cur\Next
    EndIf
    *cLL = *LL\Cur\Prev
    FreeMemory(*LL\Cur)
    *LL\Cur = *cLL
    *LL\Count-1
    ProcedureReturn #True
  EndIf
EndProcedure

Procedure LL_Free(*LL.LL_Header)
  *LL\Cur = #Null
  While *LL\Count
    LL_Delete(*LL)
  Wend
  FreeMemory(*LL)
EndProcedure

Procedure LL_Count(*LL.LL_Header)
  ProcedureReturn *LL\Count
EndProcedure

; ------------------------------------------------------------------------------------
;- Steuerung
; ------------------------------------------------------------------------------------

Procedure LL_Next(*LL.LL_Header)
  If *LL\Cur
    If *LL\Cur\Next
      *LL\Cur = *LL\Cur\Next
      ProcedureReturn #True
    EndIf
  ElseIf *LL\First
    *LL\Cur = *LL\First
    ProcedureReturn #True
  EndIf
EndProcedure

Procedure LL_Prev(*LL.LL_Header)
  If *LL\Cur
    If *LL\Cur\Prev
      *LL\Cur = *LL\Cur\Prev
      ProcedureReturn #True
    EndIf
  ElseIf *LL\Last
    *LL\Cur = *LL\Last
    ProcedureReturn #True
  EndIf
EndProcedure

Procedure LL_Reset(*LL.LL_Header)
  *LL\Cur = #Null
EndProcedure

Procedure LL_First(*LL.LL_Header)
  LL_Reset(*LL.LL_Header)
  LL_Next(*LL.LL_Header)
EndProcedure

Procedure LL_Last(*LL.LL_Header)
  LL_Reset(*LL.LL_Header)
  LL_Prev(*LL.LL_Header)
EndProcedure

Procedure LL_GetEntry(*LL.LL_Header)
  ProcedureReturn *LL\Cur
EndProcedure

Procedure LL_SetEntry(*LL.LL_Header, Entry)
  *LL\Cur = Entry
EndProcedure

Procedure LL_SwitchNext(*LL.LL_Header)
  If *LL\Cur
    If *LL\Cur\Next
      Swap *LL\Cur\Data, *LL\Cur\Next\Data
    EndIf
  EndIf
EndProcedure

Procedure LL_SwitchPrev(*LL.LL_Header)
  Protected *DData
  If *LL\Cur
    If *LL\Cur\Prev
      Swap *LL\Cur\Data, *LL\Cur\Prev\Data
    EndIf
  EndIf
EndProcedure

; ------------------------------------------------------------------------------------
;- Lesen & Setzen
; ------------------------------------------------------------------------------------

Procedure LL_Get(*LL.LL_Header)
  If *LL\Cur
    ProcedureReturn *LL\Cur\Data
  EndIf
EndProcedure

Procedure LL_Set(*LL.LL_Header, Val)
  If *LL\Cur
    *LL\Cur\Data = Val
  EndIf
EndProcedure
Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Simples Logsystem [Include]

Beitrag von STARGÅTE »

Blöde Frage : Wieso nutzt du noch deine eigene LinkedList ?

Seit PureBasic 4.50 ist es möglich LinkedList in Strukturen zu verwenden.

Und da ich nichts am Code erkenne was "außergewöhnlich" wäre, sollte dies auch mit PB 4.50 laufen

Code: Alles auswählen

Structure Logger_Entry
  Priority.l
  Time.l
  *Message
EndStructure

Structure Logger_Data
  List Logger_Entry.Logger_Entry()
  MinViewPriority.l
  Enable.a
EndStructure
Wenn du willst schreib ich dir den Code um, oder du machst es selber, aufjedenfall sollte es dadurch schneller und sicherer Laufen, als jetzt wo du es "per Hand" machst
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: Simples Logsystem [Include]

Beitrag von cxAlex »

Gewohnheitssache :P

Ich habe viele Codes in denen ich massig Dynamische Elemente mit LinkedLists erstelle, auch aus der Zeit wo das noch nicht nativ war und das hab ich mir halt beibehalten.

Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Simples Logsystem [Include]

Beitrag von STARGÅTE »

"Gewohnheitssache :P"

Für dich schon, für Leute die erst mit 4.50 in PureBasic eingestiegen sind, nicht.

Hier mal mein Vorschlag für eine minimalistische Version (komplett ohne AllocateMemory :twisted: )
(Kommentare habich mal weggelassen)

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Einfaches Logsystem
; Author: Alexander Aigner
; PB 4.4+ x86/x64 Ascii/Unicode
; Update to 4.50 by STARGÅTE
; ------------------------------------------------------------------------------------
EnableExplicit

Structure Logger_Entry
  Priority.i
  Time.i
  Message$
EndStructure

Structure Logger_Data
  List Entry.Logger_Entry()
  *Current.Logger_Entry
  MinViewPriority.i
  Enable.i
EndStructure

Global NewList Logger_Data.Logger_Data()

Enumeration
  #Logger_Info
  #Logger_Warning
  #Logger_Error
EndEnumeration

Procedure Logger_New()
  AddElement(Logger_Data())
  Logger_Data()\Enable = #True
  ProcedureReturn Logger_Data()  
EndProcedure

Procedure Logger_Clear(*Logger.Logger_Data)
  ClearList(*Logger\Entry())
EndProcedure

Procedure Logger_Free(*Logger.Logger_Data)
  ChangeCurrentElement(Logger_Data(), *Logger)
  DeleteElement(Logger_Data())
EndProcedure

Procedure Logger_Enable(*Logger.Logger_Data, Enable = #True)
  *Logger\Enable = Enable 
EndProcedure

Procedure Logger_Log(*Logger.Logger_Data, Message$, Priority = #Logger_Info)
  If Message$ And *Logger\Enable
    LastElement(*Logger\Entry())
    AddElement(*Logger\Entry())
  	*Logger\Entry()\Time = Date()
    *Logger\Entry()\Priority = Priority
    *Logger\Entry()\Message$ = Message$
  EndIf 
EndProcedure

Procedure Logger_StartView(*Logger.Logger_Data, MinimumViewPriority = #Logger_Info)
  ResetList(*Logger\Entry())
  *Logger\MinViewPriority = MinimumViewPriority
EndProcedure

Procedure Logger_ViewNext(*Logger.Logger_Data)
  Protected RtVar
  *Logger\Current = #Null
  While NextElement(*Logger\Entry())
    If *Logger\Entry()\Priority >= *Logger\MinViewPriority
      *Logger\Current = *Logger\Entry()
      ProcedureReturn #True
    EndIf
  Wend
EndProcedure

Procedure Logger_GetTime(*Logger.Logger_Data)
  If *Logger\Current
    ProcedureReturn *Logger\Current\Time  
  EndIf
EndProcedure

Procedure Logger_GetPriority(*Logger.Logger_Data)
  If *Logger\Current
    ProcedureReturn *Logger\Current\Priority 
  EndIf
EndProcedure

Procedure.s Logger_GetMessage(*Logger.Logger_Data)
  If *Logger\Current
    ProcedureReturn *Logger\Current\Message$
  EndIf
EndProcedure 
Hat den selben Input/Output ist also zu 100% kompatibel, wird halt nur anders verwaltet.
Kannst ja wiederum deiner Seits mal "auswechseln" und mir sagen ob noch geht ...
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: Simples Logsystem [Include]

Beitrag von cxAlex »

Haut schon so hin wie du's gemacht hast. Nur das Global mag ich nicht, ich hab das ganze lieber schön abgekapselt, das meide ich wie GoTo :mrgreen:

Naja, wie du gesagt hast der Input/Output ist derselbe, kann man also machen wie man will.
"Gewohnheitssache :P"

Für dich schon, für Leute die erst mit 4.50 in PureBasic eingestiegen sind, nicht.
Bin ich aber nicht :wink:

Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Simples Logsystem [Include]

Beitrag von GPI »

Das Logsystem ist so realtiv unbrauchbar. Ein Logsystem kommt vorallen dann zu tragen, wenn ein Programm mal abschmiert. Und da bei dir nichts gespeichert wird, ist dann auch alles weg. Auch wertet man in der Regel nachträglich eine Logdatei aus.

Wichtig ist allerdings, das du die Datei dann ohne Schreibcache öffnest! Bzw. den OS sagst, das er sofort alle daten schreiben soll. Die schlampigste Methode wär, diese Datei gleich zu schließen und wieder zu öffnen. Das kann aber bei einer großen Logdatei *erhebliche* Performance-probleme mit einen Virenscanner geben (der die Datei bei jeden öffnen/schließen komplett überprüfen kann).

p.s.: Ich würde auch auf die linkedlist.pbi verzichten. Es machts nur komplizierter. LinkedList kann man auch per Parameter übergeben.

p.p.s.: die LinkedList.pbi find ich schon etwas lustig. Legt die wirklich für jeden einzelnen Speicherfetzen einen eigenen Block an? Defragmentiert das den Speicher auf dauer nicht ziemlich?
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: Simples Logsystem [Include]

Beitrag von cxAlex »

Es soll auch eher kleine Informationen loggen, Siehe Firefox Java-Console ... .

Ich hab mein Include angepasst, es wrappt nun die neuen dynamischen PB - Listen in Macros, werds demnächst mal hochladen.

Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Antworten