Jump to content

Problems tailing a log file


Recommended Posts

I sort of have a whole slew of questions and would appreciate any help with any of them.

To sumarize, I'm trying to follow my EQ2 log file and look for certain text. (I've mostly got the TeamSpeak remote dll working with AutoIT, so one of the thing I'd like to be able to do is control that without leaving the game.) (And I'll be posting the teamspeak stuff if anyone is interested.)

Anyhow, the first and most annoying question:

When the script loads, I can read to the end of the file, but even if new data is written to the file, it never advances past that EOF unless I shut off logging in the game and then re-enable it. (Presumably havging the game close the file and reopen it.) I'm just using FileRead, and it works except for the EOF thing, so I don't think there's a problem with me code - but I'll post it if someone disagrees. Anyhow, is there some way around my problem? Some UDF that opens and reads files in a different way or something?

Second question... I dont see a way within AutoIT to move the file cursor to the end of the file without reading the whole thing in. Is there a shortcut to skip to the end of the file?

Third question... If I've opened a file, is it possible to see if another process also has it open? e.g. Am I looking at the right file, does the EQ client have it open for writing? This'd mae it easier to autoscan the file rather than hand selecting it, like I do now.

Again, thanks for any help anyone can provide!

Link to comment
Share on other sites

Please post that I would like to see it :(

You will probally have the script sleep and loop to reload the text file my thoughts would be it can't read something that doesnt exist or using filereadline pause at the eof.

Func RELOAD()
SLEEP(5000)
FileClose($file)
$file = FileOpen("EQ2.LOG", 0)
While 1
    $line = FileReadLine($file)
    If @error = -1 Then RELOAD()
    MsgBox(0, "Line read:", $line)
Wend
ENDFUNC
FileClose($file)

Dunno _FileCountLines perhaps?

Checking Open File handles would be my suggestion.

http://www.microsoft.com/windows2000/techi...isting/oh-o.asp

I didn't test that I just thought of it, if it doesnt work let me know.

Link to comment
Share on other sites

I made a very simiilar script for EQ when I was playing it.

First I read the entire file into a variable, and stringsplit it by @lf

that gave me how many roughly line feeds it had. ( remember it adds one for the last, and there is a blank line as well at the end.

I stored the adjusted number in an ini file so I didn't have to do it every time.

Next I set up a simple loop to find if a new line had been added.

while 1

$line=filereadline($filename,$linecount)

if Stringlen($line)>2 then dofunc()

sleep(100)

wend

for the dofunc() I had it process the information on that line. ( I searched for certain text) oh yea, and make it add one to $linecount.

Anyway you get the idea.

One part would play a certain tune when anyone in my list of names sent me a tell.

In later scripts, I had my enchanter set up to cast Kei on any of my friends who came by and said hi. Just have them put anything in the trade window (targets them automatically) and then send the magic tell.

give it a try yourself, if you can't figure it out, I will post the solution.

Edited by scriptkitty

AutoIt3, the MACGYVER Pocket Knife for computers.

Link to comment
Share on other sites

Ok, for reference - here's the main loop of the program:

If $p_State = $PROGRUNNING then
    If TimerDiff( $i_tFileRead ) > 100 and StringLen( $s_FileBuf )<57000 then
      $s_FileBuf = FileRead( $i_LogFile, 8192 )
      $i_ReadError = @error
      $s_LogFile = $s_LogFile & StringLower( $s_FileBuf )
      if $i_ReadError = 1 then 
        MSGBox( 4096, "File Error", "Error reading from file: " & $s_LogFileName )
        $g_Msg = $GUI_EVENT_CLOSE
      endif
      if $i_ReadError = -1 then 
        GuiCtrlSetState( $g_lSynchronized, $GUI_SHOW );
        $i_tFileRead = TimerInit();     
      endif
    endif

    $s_LogLine=""
    if $s_LogFile <> "" then

Blah Blah Blah

Anyhow, that part is the one thing that works, and processes lines faster than I've managed to kick them out even with tons of battle spam around me.

The problem in my first question is that if the log file has

Log line 1
Log line 2
Log line 3

in it when I load and start the script, all my program ever sees is Log line 3, even when the game writes Log line 4, and 5 and 100... I'll still be looking at "Last line read: Log line 3", unless I tell the game to close and reopen its log.

I found FileReadLine with a line number seemed to slow the program way down - and incidentally, the game too... FileReadLine without a line number got behind in processing in spammy areas. So, I moved to FileRead in 8k blocks and just search for the strings I'm interested in or throw the whole thing away.

I just need to get past the phantom EOF.

Relating to part 2:

Now, for the dumb question, to get to the end of file really quickly, can I just do a FileRead( $i_LogFile, $unreasonably_large_number)?

Link to comment
Share on other sites

Ok, I got my answer for part 1 of my problem as well.

I've been able to adapt the _RealFileRead Function to read past the end of the file at program launch. Or rather, that function did it on it's own, and now I've adapted it to a new home in my program. All that remains is to speed test it, but I'm imagining it will be fast.

Nice work with that, BTW, Larry if you ever see this :(

Now all that leaves is trying to figure out which log file EQ2 has open automagically, since it changes depending on which character is logged in. I looked briefly at the open handles suggestion above, but it seems to be a whole application, and I don't really want to open another window and run a full app. Especially since I'll have to do it on a semi-regular basis so the program can keep up with when I log in my alts :

So, thanks for all the help so far.

Edit: OMG, is it fast. Processed about 3 weeks of log in 54 seconds. Must mean I'm going to need to write more features :(

I modified it a little so the part of the RealFileRead that makes the string to put the return data in doesn't have to run 10 times a second:

Func _RealFileRead2( $hFile, ByRef $RFR_str )
   Local $RFR_ret
   Local $RFR_r
   Local $RFR_b

   $RFR_b = StringLen( $RFR_str ) -1

   $RFR_r = DllCall( "kernel32.dll", "int", "ReadFile",_
                     "hwnd", $hFile,_
                     "str",$RFR_str,_
                     "long",$RFR_b,_
                     "long_ptr",0,_
                     "ptr",0 )

   $RFR_ret = $RFR_r[4]
   $RFR_str = $RFR_r[2]
   Return $RFR_ret
EndFunc

Just keep passing it the same string every time I call the function. Seemed like a place to save a little overhead.

Edited by mother9987
Link to comment
Share on other sites

  • 1 year later...

Ok, I got my answer for part 1 of my problem as well.

I've been able to adapt the _RealFileRead Function to read past the end of the file at program launch. Or rather, that function did it on it's own, and now I've adapted it to a new home in my program. All that remains is to speed test it, but I'm imagining it will be fast.

Nice work with that, BTW, Larry if you ever see this :)

Now all that leaves is trying to figure out which log file EQ2 has open automagically, since it changes depending on which character is logged in. I looked briefly at the open handles suggestion above, but it seems to be a whole application, and I don't really want to open another window and run a full app. Especially since I'll have to do it on a semi-regular basis so the program can keep up with when I log in my alts :)

So, thanks for all the help so far.

Edit: OMG, is it fast. Processed about 3 weeks of log in 54 seconds. Must mean I'm going to need to write more features :whistle:

I modified it a little so the part of the RealFileRead that makes the string to put the return data in doesn't have to run 10 times a second:

Func _RealFileRead2( $hFile, ByRef $RFR_str )
   Local $RFR_ret
   Local $RFR_r
   Local $RFR_b

   $RFR_b = StringLen( $RFR_str ) -1

   $RFR_r = DllCall( "kernel32.dll", "int", "ReadFile",_
                     "hwnd", $hFile,_
                     "str",$RFR_str,_
                     "long",$RFR_b,_
                     "long_ptr",0,_
                     "ptr",0 )

   $RFR_ret = $RFR_r[4]
   $RFR_str = $RFR_r[2]
   Return $RFR_ret
EndFunc

Just keep passing it the same string every time I call the function. Seemed like a place to save a little overhead.

I'm very new to Autoit and I just don't understand this script entirely. Would it be possible to either post more of the script or explain how it works?

Thank you, It's awesome to have good coders who are willing to share with those of us trying to learn.

Link to comment
Share on other sites

Having problems understanding the syntax of the DLLCall? The AutoIT help file may be of assistance.

Having problems with understanding the function and parameters being used? The Microsoft website should have documentation about kernel32.dll.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...