none
Regex Ausdruck um mehrere Strings aus einem log-file zu erfassen RRS feed

  • Frage

  • Hallo zusammen,

    Möchte ein log-file einlesen und dieses nach einem bestimmten String suchen.

    Das log-file sieht in etwas so aus:

      -----------------------------------------------------------------------

    MAXL> alter database S.T reset data;

     OK/INFO - 1054014 - .....
     OK/INFO - 1051061 - .....


          essmsh timestamp: Fri Jun 01 09:15:07 2012

    MAXL> IMPORT database ..... 
       2> connect as .....
       3> connect as ....


     OK/INFO - 1021041 - Connection String is [DSN=HP_Master;UID=...;PWD=...;].
     OK/INFO - 1021006 - SELECT Statement [SELECT column1,column2,... WHERE id > 10] is generated.
     OK/INFO - 1021043 - Connection has been established. OK/INFO - 102104

     OK/INFO - 1021047 - Finished fetching data.
     OK/INFO - 1021002 - SQL Connection is Freed.
     OK/INFO - 1007132 - Building Dimensions Elapsed Time : [8.289] seconds.
     OK/INFO - 1021004 - Connection String is generated.

    --------------------------------------------------------------------------

    So jetzt möchte ich:

    "Fri Jun 01 09:15:07 2012" ,

    "S.T" ,

    "SELECT column1,column2,... WHERE id > 10" ,

    "[8.289]"

    rausfiltern und in ein neues txt oder log-file speichern. Wobei das Datum und S.T nur einmal im log-file vorkommen und das SQL-query und die Elapsed Time  öfters. Die soll er auch alle hinschreiben. Weiß jemand wie ich das am besten hinbekomme?

    mfg



    Mittwoch, 6. Juni 2012 06:37

Antworten

  • >wenn mein Ausdruck über zwei oder mehrere Zeilen geht, diese auch erfassen?
     

    Um einen Zeilenumbruch im Muster zu definieren geht in der Regel "`n".

    Das nächste Problem ist aber, das get-content ein Array aus einzelnen Zeilen erzeugt, mit Zeilenumbrüchen als Trenner.

    Wir brauchen aber den ganzen Text (mit Zeilenumbrüchen!) um einen Zweizeiler (oder n-zeiler) erkennen zu können. Daher musst du als Trennzeichen einen Null-Delimiter angeben, um einen einzelnen String mit Zeilenumrüchen zu erhalten und durchsuchen zu können. Das geht mit "-delimiter `0".


     
    > bräuchte ich auch noch einen Verbesserungsvorschlag, da ich nur die Datenbank also [a-z]+\.[a-z]+ erfassen möchte. 

     

    Wenn du kein eindeutiges Muster findest um den gesuchten Wert nach "Datenbank" zu identifizieren, lässt du das Muster so und entfernst einfach nachträglich den unerwünschten Teil.

    Dazu müssen wir das ganze aber etwas umbauen und die Pipeline aufdröseln. Dann kannst du nach belieben Strings nachbearbeiten bevor sie ausgeben werden.

       

    Damit das Wort "Datenbank" wirklich nur in diesem einen Fall entfernt wird, prüfst du auf das richtige Suchmuster und machst ein einfaches replace.

    Im Ganzen: 

    $log = "d:\log.txt"
    $newfile = "D:\newfile.txt"
    
    # Suchmuster festlegen
    $suchmuster = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}","database [a-z]+\.[a-z]+","\[SELECT.*\]","\[SELECT.*`n.*\]","\[[0-9]+.[0-9]{1,3}\]")
    
    # log einlesen
    $logcontent = gc $log -Delimiter "`0"
    
    # Suche jedes Muster und schreibe in Ausgabefile
    foreach ($muster in $suchmuster) {
    		if ($result = (Select-String -AllMatches -Pattern $muster -InputObject $logcontent  | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty value )) {
    			if ($muster -like "database*" ) { $result = $result.replace("database ","")}
    			# etc...
    			write-output $result
    			Add-Content $newfile $result
    		}
    }
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".



    Freitag, 8. Juni 2012 14:22
    Moderator
  • >Nur ein kleines Problem hab ich noch, er findet bei mir keine replace-methode

    Soso. Ich nehme an du hast einen Test mit zwei "Database"-Einträgen im Log gemacht. Also mit einem Fall von dem du am Anfang erklärt hast, er käme nicht vor. ;-)

    Ist aber kein Problem. Der Fehler besteht darin das in diesem Fall das Ergebnis kein einzelner String mehr ist (der die Replace-Methode hat), sondern ein Array aus mehreren Strings. Daher füttern wir einfach das Ergebnis in eine Pipeline und dann geht es auch mit einem Array:
         

    if ($muster -like "database*" ) { $result =  $result | ForEach-Object { $_.replace("database ","")} }
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:37
    • Tag als Antwort aufgehoben speedcar343 Montag, 11. Juni 2012 05:39
    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:46
    • Tag als Antwort aufgehoben speedcar343 Montag, 11. Juni 2012 05:46
    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:47
    Sonntag, 10. Juni 2012 19:38
    Moderator
  • Schön das du mit den Anforderungen nur stückchenweise rausrückst, das machts viel spannender...

    Im Ernst, das Problem ist nun, das die zeilenweise - und damit abwechselnde Abfrage einfach möglich gewesen wäre, bevor wir das Script umgebaut haben um mehrzeilige Texte zu erfassen. Eigentlich müssten wir wieder von vorne Anfangen, wieder auf zeilenweise Suche umstellen und eine neue Methode für die Mehrzeiler finden....

    ... glücklicherweise :) werden aber bei den Matches außer dem eigentlichen Fundstring auch die Position im Text gespeichert. Wir bauen also das ganze dahingehend um, das zuerst alle Funde in einem Array gespeichert werden, sortieren dann nach ihrer Position im Text und machen zuletzt erst das Replace und die Ausgabe:

    $allmatches = @() 
    $log = "d:\log.txt"
    $newfile = "D:\newfile.txt"
    
    # Suchmuster festlegen
    $suchmuster = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}","database [a-z]+\.[a-z]+","\[SELECT.*\]","\[SELECT.*`n.*\]","\[[0-9]+.[0-9]{1,3}\]")
    
    # log einlesen
    $logcontent = gc $log -Delimiter "`0"
    
    # Suche jedes Muster 
    foreach ($muster in $suchmuster) {
    		$allmatches  += Select-String -AllMatches -Pattern $muster -InputObject $logcontent | Select-Object -ExpandProperty matches 
    }
    
    # sortiere matches nach Position im Text und schreibe in File
    $allmatches | sort Index | Select-Object -ExpandProperty value | ForEach-Object {
    
    	if ($_ -match "database [a-z]+\.[a-z]+" ) { $_ = $_.replace("database ","") }
    	
    	# andere Ersetzungen hier...
    	
    	#Ausgabe
    	write-output $_
    	Add-Content $newfile $_
    }
     


    Grüße, Denniver



    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Dienstag, 12. Juni 2012 10:24
    Moderator
  • "\[SELECT(.+,.+`n){1,}.*\]"

    Das war doch etwas komplizierter als zuerst gedacht. Sorry :) Ich dachte einfach an den Quantifizierer {n,n}, das Problem war aber, das bei n-möglichen Zeilen ohne weitere Einschränkung auch das komplette Log passt. :)

    Drum musste eine weitere Einschränkung gefunden werden. Ich habe jetzt mangels Orginaldaten als Bedingung "mindestens ein Komma" muß in der Zeile vor dem Zeilenumbruch vorkommen.

    Falls das zu den Originaldaten nicht passt müssten wir nochmal justieren. In diesem Fall müsstest du mal einen repräsentativen Auszug aus dem Log posten.
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    • Als Antwort markiert speedcar343 Freitag, 15. Juni 2012 06:45
    Donnerstag, 14. Juni 2012 16:42
    Moderator
  • Hier, das sollte gehen:

     
    cls
    
    $output = @()
    $newfile = "D:\data\LogFilter.txt"
    $path = "D:\log\"
    $files = @(Get-Childitem $path -filter "*.log" -recurse)
    
    foreach ($file in $files) {
    	$log = $file.FullName
    
    	# Suchmuster festlegen
    	$TimeStPattern ="[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}"
    	$DbPattern =  "database [a-z]+\.[a-z]+"
    	$SelectPattern = "\[SELECT(.+,.+`n){0,}.*\]" 
    	$ElapsedTimePattern = "\[[0-9]+\.[0-9]{1,3}\]"
        
    	# log einlesen
    	$logcontent = gc $log -Delimiter "`0"
    	write-output "-----------------------------------`n"
    	write-output $file.name
    	AC $newfile "-----------------------------------"
    	Add-Content $newfile $file.name
    
    	#Suchmuster für den ersten Timestamp und Database (ohne den parameter "Allmatches" wird automatisch nur der erste Fund berücksichtigt 
    	$timestamp  = Select-String  -Pattern $TimeStPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty Value
    	$database  = (Select-String  -Pattern $DbPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty Value).replace("database ","")
    	
    	# Suchmuster für jedes SELECT und Elapsed Time 
    	$selectMatches = @(Select-String -AllMatches -Pattern $SelectPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | sort Index | Select-Object -ExpandProperty value)
    	$ElapsedTimeMatches = @(Select-String -AllMatches -Pattern $ElapsedTimePattern -InputObject $logcontent | Select-Object -ExpandProperty matches | sort Index | Select-Object -ExpandProperty value)
    	
    	# Ausgabe generieren
    	for  ( $i = 0; $i -lt $selectMatches.Count; $i ++ ) {
    	$selectmatch = $selectMatches[$i].replace("`n","")
    	 $output += "$timestamp $database $selectmatch $($ElapsedTimeMatches[$i])"
    	}
    	
    	#Ausgabe
    	write-output $output
    	Add-Content $newfile $output
    	
    }

    Schau mal ob die Änderungen alle verstehst, sonst frag noch mal.

    Grüße, Denniver



    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Montag, 18. Juni 2012 10:15
    Moderator

Alle Antworten

  • Ich habe dir mal das Grundgerüst gebaut und als Beispiel das Suchmuster für das Select-Statement. Schau mal ob du die Anderen selbst herausbekommst.
    Dir soll ja nicht langweilig werden... :)  (Hilfe bei den Regex-Ausdrücken gibts z.b. hier.)

     
    $log = "d:\log.txt"
    $newfile = "D:\newfile.txt"
    
    # Suchmuster festlegen
    $suchmuster = @("\[SELECT.*\]","zweitesSuchmuster","drittesSuchmuster","viertesSuchmuster")
    
    # log einlesen
    $logcontent = gc $log 
    
    # suche jedes muster und schreibe in Ausgabefile
    foreach ($muster in $suchmuster) {
      $logcontent | Select-String -AllMatches $muster | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty value | Add-Content $newfile 
    }
     

    Grüße, Denniver



    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".


    Mittwoch, 6. Juni 2012 10:41
    Moderator
  • Also langweilig wird mir ganz sicher nicht, wenn ich schon seit stunden daran arbeite und suche und zu keinem ergebnis komme...

    Aber vielen dank! damit kann ich jetzt endlich was anfangen! werde dann mein Ergebnis posten :)

    sollte ich trotzdem nicht weiter kommen geb ich natürlich auch bescheid ;)

    Mittwoch, 6. Juni 2012 11:41
  • so jetzt hab ich noch eine frage:

    wie kann ich, wenn mein Ausdruck über zwei oder mehrere Zeilen geht, diese auch erfassen?

    z.B.: [SELECT column1,column2,

    column3, column4,... WHERE id > 10


    Die grenzen sollen ja die eckigen Klammern sein. Hab es schon mit -context probiert, allerdings ohne Erfolg.

    Mein Suchmuster sieht derzeit folgendermaßen aus. Würde mich auch über Verbesserungsvorschläge freuen.

    $suchmuster = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}",

    "MAXL> alter database [a-z]+\.[a-z]+","\[SELECT.*\]","\[[0-9]+.[0-9]{1,3}\]")

    Beim 3. Muster "MAXL> alter database" bräuchte ich auch noch einen Verbesserungsvorschlag, da ich nur die Datenbank also [a-z]+\.[a-z]+ erfassen möchte.  Also bräuchte ich eine Vorlage, die mir nur den Text ausgibt, der Rechts von diesem Ausdruck steht. Wäre super wenn jemand eine idee hätte.

    Bin noch Anfänger, daher bitte um Verständnis für mein unwissen...




    Freitag, 8. Juni 2012 05:45
  • >wenn mein Ausdruck über zwei oder mehrere Zeilen geht, diese auch erfassen?
     

    Um einen Zeilenumbruch im Muster zu definieren geht in der Regel "`n".

    Das nächste Problem ist aber, das get-content ein Array aus einzelnen Zeilen erzeugt, mit Zeilenumbrüchen als Trenner.

    Wir brauchen aber den ganzen Text (mit Zeilenumbrüchen!) um einen Zweizeiler (oder n-zeiler) erkennen zu können. Daher musst du als Trennzeichen einen Null-Delimiter angeben, um einen einzelnen String mit Zeilenumrüchen zu erhalten und durchsuchen zu können. Das geht mit "-delimiter `0".


     
    > bräuchte ich auch noch einen Verbesserungsvorschlag, da ich nur die Datenbank also [a-z]+\.[a-z]+ erfassen möchte. 

     

    Wenn du kein eindeutiges Muster findest um den gesuchten Wert nach "Datenbank" zu identifizieren, lässt du das Muster so und entfernst einfach nachträglich den unerwünschten Teil.

    Dazu müssen wir das ganze aber etwas umbauen und die Pipeline aufdröseln. Dann kannst du nach belieben Strings nachbearbeiten bevor sie ausgeben werden.

       

    Damit das Wort "Datenbank" wirklich nur in diesem einen Fall entfernt wird, prüfst du auf das richtige Suchmuster und machst ein einfaches replace.

    Im Ganzen: 

    $log = "d:\log.txt"
    $newfile = "D:\newfile.txt"
    
    # Suchmuster festlegen
    $suchmuster = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}","database [a-z]+\.[a-z]+","\[SELECT.*\]","\[SELECT.*`n.*\]","\[[0-9]+.[0-9]{1,3}\]")
    
    # log einlesen
    $logcontent = gc $log -Delimiter "`0"
    
    # Suche jedes Muster und schreibe in Ausgabefile
    foreach ($muster in $suchmuster) {
    		if ($result = (Select-String -AllMatches -Pattern $muster -InputObject $logcontent  | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty value )) {
    			if ($muster -like "database*" ) { $result = $result.replace("database ","")}
    			# etc...
    			write-output $result
    			Add-Content $newfile $result
    		}
    }
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".



    Freitag, 8. Juni 2012 14:22
    Moderator
  • Denniver ich bin beeindruckt!!! Vielen Dank!

    Nur ein kleines Problem hab ich noch, er findet bei mir keine replace-methode:

    -------------------------------------------------------------------------------

    Fehler beim Aufrufen der Methode, da [System.Object[]] keine Methode mit dem Namen "replace" enthält.
    Bei C:\Users\lf.ps1:19 Zeichen:63
    +             if ($muster -like "database*" ) { $result = $result.replace <<<< ("database ","")}
        + CategoryInfo          : InvalidOperation: (replace:String) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound

    --------------------------------------------------------------------------------

    mein OS: windows vista x86

    hab mich schon umgeschaut bei den powershell guys, dieser empfiehlt ein $result = $result | out-string
    zeigt aber auch keine Wirkung...

    (source: http://thepowershellguy.com/blogs/posh/archive/2007/02/27/hey-powershell-guy-how-can-i-tally-up-all-the-words-found-in-a-text-file.aspx)




    Sonntag, 10. Juni 2012 15:24
  • >Nur ein kleines Problem hab ich noch, er findet bei mir keine replace-methode

    Soso. Ich nehme an du hast einen Test mit zwei "Database"-Einträgen im Log gemacht. Also mit einem Fall von dem du am Anfang erklärt hast, er käme nicht vor. ;-)

    Ist aber kein Problem. Der Fehler besteht darin das in diesem Fall das Ergebnis kein einzelner String mehr ist (der die Replace-Methode hat), sondern ein Array aus mehreren Strings. Daher füttern wir einfach das Ergebnis in eine Pipeline und dann geht es auch mit einem Array:
         

    if ($muster -like "database*" ) { $result =  $result | ForEach-Object { $_.replace("database ","")} }
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:37
    • Tag als Antwort aufgehoben speedcar343 Montag, 11. Juni 2012 05:39
    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:46
    • Tag als Antwort aufgehoben speedcar343 Montag, 11. Juni 2012 05:46
    • Als Antwort markiert speedcar343 Montag, 11. Juni 2012 05:47
    Sonntag, 10. Juni 2012 19:38
    Moderator
  • So vielen Danke für die Mühe, jetzt klappts :)
    Montag, 11. Juni 2012 05:48
  • In meinem jetzigen Script schreibt er mir zuerst alle Select-Muster und anschließend alle Zeit-Muster. Jetzt hätte ich noch eine frage, ist es möglich die Zeilen abwechselnd auch zu schreiben, sprich zuerst Select-Statement dann Elapsed-Time. Ich meine so:

    [SELECT......]

    [8.289]

    [SELECT.....]

    [3.765]

    [SELECT.....]

    [6.987]

    oder muss man da wieder eine andere Strategie anwenden?


    Dienstag, 12. Juni 2012 07:11
  • Schön das du mit den Anforderungen nur stückchenweise rausrückst, das machts viel spannender...

    Im Ernst, das Problem ist nun, das die zeilenweise - und damit abwechselnde Abfrage einfach möglich gewesen wäre, bevor wir das Script umgebaut haben um mehrzeilige Texte zu erfassen. Eigentlich müssten wir wieder von vorne Anfangen, wieder auf zeilenweise Suche umstellen und eine neue Methode für die Mehrzeiler finden....

    ... glücklicherweise :) werden aber bei den Matches außer dem eigentlichen Fundstring auch die Position im Text gespeichert. Wir bauen also das ganze dahingehend um, das zuerst alle Funde in einem Array gespeichert werden, sortieren dann nach ihrer Position im Text und machen zuletzt erst das Replace und die Ausgabe:

    $allmatches = @() 
    $log = "d:\log.txt"
    $newfile = "D:\newfile.txt"
    
    # Suchmuster festlegen
    $suchmuster = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}","database [a-z]+\.[a-z]+","\[SELECT.*\]","\[SELECT.*`n.*\]","\[[0-9]+.[0-9]{1,3}\]")
    
    # log einlesen
    $logcontent = gc $log -Delimiter "`0"
    
    # Suche jedes Muster 
    foreach ($muster in $suchmuster) {
    		$allmatches  += Select-String -AllMatches -Pattern $muster -InputObject $logcontent | Select-Object -ExpandProperty matches 
    }
    
    # sortiere matches nach Position im Text und schreibe in File
    $allmatches | sort Index | Select-Object -ExpandProperty value | ForEach-Object {
    
    	if ($_ -match "database [a-z]+\.[a-z]+" ) { $_ = $_.replace("database ","") }
    	
    	# andere Ersetzungen hier...
    	
    	#Ausgabe
    	write-output $_
    	Add-Content $newfile $_
    }
     


    Grüße, Denniver



    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Dienstag, 12. Juni 2012 10:24
    Moderator
  • Dankeschön Denniver, funktioniert Perfekt!!! =)
    die Sache ist, dass ich vorher gerne selbst auf die Lösung kommen möchte. Bin ja noch in der lernphase :)
    Die andere Sache ist, dass ich oft erst später auf Mängel in meiner Denkweise komme. Da ist mir leider schon wieder einer eingefallen:
    Ist es auch möglich ein dynamisches Muster zu verwenden für \[SELECT.*`n.*`n.*\], \[SELECT.*`n.*`n.*`n.*\] , ... usw.?

    Tut mir echt leid, aber ich bemerke sowas erst im nachhinhein wenn etwas fehlt :(
    da ich log-files habe die Statements enthalten, welche weit über 2-3 Zeilen hinaus gehen.

    Vielleicht kannst du mir eine geeignete Lektüre für Automationen mit Powershell empfehlen?

    lg speedy

    Dienstag, 12. Juni 2012 14:46
  • > die Sache ist, dass ich vorher gerne selbst auf die Lösung kommen möchte. Bin ja noch in der lernphase :)
    >
    Ist es auch möglich ein dynamisches Muster zu verwenden für \[SELECT.*`n.*`n.*\], \[SELECT.*`n.*`n.*`n.*\] , ... usw.?
     
    Na wenn du erstmal selbst auf die Lösung kommen möchtest, dann verrate ich dir nur folgendes: Ja, das geht und du hast die Lösung bereits in den von dir erstellten Regex-Mustern benutzt. :)
     
    >geeignete Lektüre für Automationen mit Powershell empfehlen?

    Auf deutsch + sehr zu empfehlen sind die Bücher von Tobias Weltner, auf englisch gibt es aber auch noch etliche, da würd ich bei Amazon o.ä. mal reinlesen.

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".


    Dienstag, 12. Juni 2012 15:14
    Moderator
  • Also kann die Lösung nicht weit weg sein :)
    Ich würde eh gern selbst drauf kommen...

    Macht zwar noch nicht was ich will, aber lieg ich auf den richtigen weg?

    "\[SELECT.*`n{0,}.*\]"   "\[SELECT.*[`n.*]{0,}\]"  "\[SELECT.*`n+.*\]"    "\[SELECT.*[\n\r]{0,}.*\]"  oder  "\[SELECT.*[\s]{0,}.*\]"

    Dienstag, 12. Juni 2012 18:57
  • Und hats geklappt oder brauchst du die Auflösung? :)

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Donnerstag, 14. Juni 2012 13:18
    Moderator
  • Ja bitte um die Auflösung, hab eig. so ziemlich alle Möglichkeiten durch, aber nichts brauchbares gefunden :-\
    Donnerstag, 14. Juni 2012 14:23
  • "\[SELECT(.+,.+`n){1,}.*\]"

    Das war doch etwas komplizierter als zuerst gedacht. Sorry :) Ich dachte einfach an den Quantifizierer {n,n}, das Problem war aber, das bei n-möglichen Zeilen ohne weitere Einschränkung auch das komplette Log passt. :)

    Drum musste eine weitere Einschränkung gefunden werden. Ich habe jetzt mangels Orginaldaten als Bedingung "mindestens ein Komma" muß in der Zeile vor dem Zeilenumbruch vorkommen.

    Falls das zu den Originaldaten nicht passt müssten wir nochmal justieren. In diesem Fall müsstest du mal einen repräsentativen Auszug aus dem Log posten.
     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    • Als Antwort markiert speedcar343 Freitag, 15. Juni 2012 06:45
    Donnerstag, 14. Juni 2012 16:42
    Moderator
  • Dankeschön :)
    Ich hoffe, dass der Task der die Logs erzeugt vor jeden Umbruch auch ein Komma  machen wird :)
    Aber wie immer erfüllt deine Vorgabe meine Wünsche zu 100%
    Mein Code sieht jetzt folgendermaßen aus:

    $newfile = "D:\data\LogFilter.txt"
    $path = "D:\log\"
    $files = @(Get-Childitem $path -filter "*.log" -recurse)
    
    foreach($file in $files){
    	$allmatches = @() 
    	$allmatches1 = @()
    	$log = "$path+$file"
    
    	# Suchmuster festlegen
    	$suchmuster1 = @("[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}","database [a-z]+\.[a-z]+")
    	$suchmuster2 = @("\[SELECT(.+,.+`n){0,}.*\]" , "\[[0-9]+\.[0-9]{1,3}\]")
        
    	# log einlesen
    	$logcontent = gc $log -Delimiter "`0"
    	write-output "-----------------------------------`n"
    	write-output $file.name
    	AC $newfile "-----------------------------------"
    	Add-Content $newfile $file.name
    
    	#Suchmuster für den ersten Timestamp und Database
    	foreach ($muster in $suchmuster1) { 
    		$allmatches1  += Select-String -AllMatches -Pattern $muster -InputObject $logcontent | Select-Object -ExpandProperty matches |  Select-Object -first 1 
    	}
    
    	# Suchmuster für jedes SELECT und Elapsed Time 
    	foreach ($muster in $suchmuster2) {
    		$allmatches += Select-String -AllMatches -Pattern $muster -InputObject $logcontent | Select-Object -ExpandProperty matches 
    	}
    
    	# sortiere matches nach Position im Text und schreibe in File
    	$allmatches | sort Index | Select-Object -ExpandProperty value | ForEach-Object {
    		if ($_ -match "database [a-z]+\.[a-z]+" ) { $_ = $_.replace("database ","") }
        		if ($_ -match "database [a-z]+\.[a-z]+" ) { $_ = $_.replace("Database ","") }
        		if ($_ -match "`n" ) { $_ = $_.replace("`n","") }
        		#$_ = $_.insert(0, $allmatches1)  --> macht nicht wie gewollt :(
    	
    	#Ausgabe
    	write-output $_
    	Add-Content $newfile $_
    	}
    
    }

    Da ich heute die Vorgabe bekommen habe den Timestamp und die Database jetzt vor jeden Select zu schreiben, und die Elapsed-Time jetzt rechts vom select-statement, hängts sich mi jetzt dort auf. Meine Versuche waren soetwa wie der insert() im Codeblock.
    Sollte jetzt so aussehen:

    Fri 23.JUN.2011 S.T [Select...] [8.123]
    Fri 23.JUN.2011 S.T [Select...] [3.123]

    bei mehrzeiler:
    Fri 23.JUN.2011 S.T [Select...
    ...] [3.123]

    Wenn es eine einfache Methode dafür gibt, wär ich sehr dankbar Denniver, ansonsten hast du schon mehr als genug für mich getan!!!



    • Bearbeitet speedcar343 Freitag, 15. Juni 2012 08:30 ergänzung
    Freitag, 15. Juni 2012 06:42
  • Ok dafür brauchen wir mal einen Auszug des Orginallogs, möglichst mit mehreren Varianten drin.

    Personenbezogene Daten oder ähnliches bitte vor dem Posten ausreichend verschleiern.

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".




    Freitag, 15. Juni 2012 10:05
    Moderator
  • Ich könnte dir den ganzen log per e-mail senden (meine: *gesnippt* falls deine mailadresse nicht für jeden sichtbar sein darf eine kurze nachricht damit ich deine hab), weil wenn ich das ganze hier rein tue verschlingt es viele Seiten, aussehen tuts nämlich genau wie ganz oben beschrieben. Hier sonst noch ein Erweiterung falls das reichen sollte mit 1-, 2- und 3-Zeiler:

    ---------------------------------------------------------------------------------> Die ersten Zeilen des Logs

    MAXL> alter object Abteilung.Bereich of type outline unlock;

     OK/INFO - 1053013 - Object [Bereich] unlocked by user [scriptuser@Native Directory].

          essmsh timestamp: Fri Jun 01 19:15:00 2012

    MAXL> alter database Abteilung.Bereich reset data;

     OK/INFO - 1054014 - Database loaded.
     OK/INFO - 1051061 - Application Vertrieb loaded - connection established.


          essmsh timestamp: Fri Jun 01 19:15:07 2012

    MAXL> IMPORT database Abteilung.Bereich dimensions 
       2> connect as "view" identified by "load" using server rules_file "m1",
      ...
      ....

      11> on error append to "D:\....";

    --------------------------------------------------------------------------> 3-Zeiler
     OK/INFO - 1021004 - Connection String is generated.
     OK/INFO - 1021041 - Connection String is [DSN=HP_Master;UID=...;PWD=...;].
     OK/INFO - 1021006 - SELECT Statement [SELECT col1,co------2,col--------3,col--------4,col----------5,col-------6,col---------7,
    col--------8,col-----------9,col----------10,col-----------11,col-----------12,col-----------13 FROM Abteilung_Bereich_Trackt
     WHERE data_storage <> 'Shared'] is generated.
     OK/INFO - 1021043 - Connection has been established.
     OK/INFO - 1021002 - SQL Connection is Freed.
     OK/INFO - 1007132 - Building Dimensions Elapsed Time : [8.289] seconds.
     OK/INFO - 1021004 - Connection String is generated.

    ----------------------------------------------------------------------> 2-Zeiler

    OK/INFO - 1021041 - Connection String is [DSN=Master;UID=...;PWD=...;].
     OK/INFO - 1021006 - SELECT Statement [SELECT col1,co------2,col--------3 FROM Abteilung_Bereich_Trackt
     WHERE data_storage <> 'Shared'] is generated.
     OK/INFO - 1021043 - Connection has been established.
     OK/INFO - 1007132 - Building Dimensions Elapsed Time : [3.583] seconds.
     OK/INFO - 1021004 - Connection String is generated.

    ----------------------------------------------------> 1-Zeiler

    OK/INFO - 1021041 - Connection String is [DSN=Server1;UID=...;PWD=...;].
     OK/INFO - 1021006 - SELECT Statement [SELECT * FROM col1.v#Abteilung#Bereich#m] is generated.
     OK/INFO - 1021043 - Connection has been established.
     OK/INFO - 1003051 - Data Load Elapsed Time for [SQL] with [m.rul] : [1670.59] seconds.
     OK/INFO - 1241113 - Database import completed ['Abteilung'.'Bereich'].

    -------------------------------------------------------------------------------------------------------------

    also der Timestamp und die Database brauch ich nur die ersten beiden Objekte sowie es beim "Select-Object -first 1" ausgeben wird.
    Das dann in jeder Zeile, genau genommen so:

    Fri Jun 01 19:15:00 2012 Abteilung.Bereich [SELECT col1,co------2,col--------3,col--------4,col----------5,col-------6,col---------7,
    col--------8,col-----------9,col----------10,col-----------11,col-----------12,col-----------13 FROM Abteilung_Bereich_Trackt
     WHERE data_storage <> 'Shared']  [1670.59]

    Fri Jun 01 19:15:00 2012 Abteilung.Bereich [SELECT col1,co------2,col--------3 FROM Abteilung_Bereich_Trackt
     WHERE data_storage <> 'Shared'] [3.583]

    Fri Jun 01 19:15:00 2012 Abteilung.Bereich [SELECT * FROM col1.v#Abteilung#Bereich#m] [1670.59]


    Lg



    Freitag, 15. Juni 2012 17:17
  • Hier, das sollte gehen:

     
    cls
    
    $output = @()
    $newfile = "D:\data\LogFilter.txt"
    $path = "D:\log\"
    $files = @(Get-Childitem $path -filter "*.log" -recurse)
    
    foreach ($file in $files) {
    	$log = $file.FullName
    
    	# Suchmuster festlegen
    	$TimeStPattern ="[a-z]{3} [a-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}"
    	$DbPattern =  "database [a-z]+\.[a-z]+"
    	$SelectPattern = "\[SELECT(.+,.+`n){0,}.*\]" 
    	$ElapsedTimePattern = "\[[0-9]+\.[0-9]{1,3}\]"
        
    	# log einlesen
    	$logcontent = gc $log -Delimiter "`0"
    	write-output "-----------------------------------`n"
    	write-output $file.name
    	AC $newfile "-----------------------------------"
    	Add-Content $newfile $file.name
    
    	#Suchmuster für den ersten Timestamp und Database (ohne den parameter "Allmatches" wird automatisch nur der erste Fund berücksichtigt 
    	$timestamp  = Select-String  -Pattern $TimeStPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty Value
    	$database  = (Select-String  -Pattern $DbPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | Select-Object -ExpandProperty Value).replace("database ","")
    	
    	# Suchmuster für jedes SELECT und Elapsed Time 
    	$selectMatches = @(Select-String -AllMatches -Pattern $SelectPattern -InputObject $logcontent | Select-Object -ExpandProperty matches | sort Index | Select-Object -ExpandProperty value)
    	$ElapsedTimeMatches = @(Select-String -AllMatches -Pattern $ElapsedTimePattern -InputObject $logcontent | Select-Object -ExpandProperty matches | sort Index | Select-Object -ExpandProperty value)
    	
    	# Ausgabe generieren
    	for  ( $i = 0; $i -lt $selectMatches.Count; $i ++ ) {
    	$selectmatch = $selectMatches[$i].replace("`n","")
    	 $output += "$timestamp $database $selectmatch $($ElapsedTimeMatches[$i])"
    	}
    	
    	#Ausgabe
    	write-output $output
    	Add-Content $newfile $output
    	
    }

    Schau mal ob die Änderungen alle verstehst, sonst frag noch mal.

    Grüße, Denniver



    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Montag, 18. Juni 2012 10:15
    Moderator
  • Wahnsinn, auf den Punkt getroffen Denniver =)
    Vielen Dank!
    Ein paar Kleinigkeiten aber noch, sobald ich mehr Files hab, fügt er die Information vom alten log zum neuen dazu.
    Das sieht dann so aus (angenommen in jedem log steht nur ein Select-Statement+ElapsedTime):

    ---------------------
    log1.log
    Fri 2011 S.T Select[col1][1.111]

    --------------------
    log2.log
    Fri 2011 S.T [Select col1 from ...][1.111]
    Fri 2011 S.T [Select col2 from ...][2.222]
    --------------------
    log3.log
    Fri 2011 S.T [Select col1 from ...][1.111]
    Fri 2011 S.T [Select col2 from ...][2.222]
    Fri 2011 S.T [Select col2 from ...][3.333]
    ----------------------------------------------

    Jetzt hab ich zur Ausgabe noch folgendes hinzugefügt

        $ouput = $null
        $output = @()

    Funktioniert auch, aber ist da vielleicht etwas zu beachten, oder ist diese Lösung in Ordnung?

    Weiters hab ich auch noch ein Problem mit der Codierung, beim abspeichern mit Add-Content erzeugt er mir rechteckige Sonderzeichen wo die Zeilenumbrüche waren im txt-file.
    Habs schon mit -Encoding -UTF8, ASCII, Unicode probiert, da wirds dann aber noch schlimmer, da ich dann nur mehr Rechtecke und Fragezeichen bekomme.


    Montag, 18. Juni 2012 12:01
  • Zur ersten Frage: Ja, das kannst du so machen.

    Zu den Sonderzeichen: Ich kann das Problem nicht nachstellen. Was benutzt du denn zum Anzeigen des Files?

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".


    Montag, 18. Juni 2012 12:25
    Moderator
  • Den ganz normalen Notepad
    Montag, 25. Juni 2012 13:11
  • Mhm ich kann dir nur anbieten das du mir mal ein Logfile und ein Ergebnisfile mit den Sonderzeichen schickst, dann schau ich sie mir mal an.

    Falls du das Log vor dem Versand editierst um sensible Daten zu entfernen, teste danach bitte nochmal ob das Problem damit immer noch auftritt. Dann gezippt(!) senden an ***

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".



    Montag, 25. Juni 2012 14:18
    Moderator
  • schon geschickt..

    lg

    Dienstag, 26. Juni 2012 10:19
  • Danke Denniver für die Mühe!

    Ja es klappt mit dem was du mir geschickt hast :)
    $selectMatches[$i].replace("`r`n","") ist die Lösung für XP und 2003!

    lg

    Freitag, 29. Juni 2012 05:40