Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
some logic help
#1
Question 
I have a UPS, and once in a while, the driver crashes for some unknown reason. It needs to be (re)started using this command: upsdrvctl start. I've written a python3 script to attempt to automatically monitor the relevant log (/var/log/syslog), and when it detects certain text, such as "Driver not connected" or "Data stale" at the end of the file, it will issue that command. That commands takes about 15s to run completely.
When I run it as is, it picks up on those error messages. Then issues the command. Then new log entries from the system (not relevant to any of this) are entered. Yet it still thinks the driver is in a bad state.
I am never good with loops, especially loops within loops. I also don't script much, so I'm sure it's messy, can be refactored, etc. Just looking to get the job done. :) I am all for simplifying the logic and learning, though!

import time
import subprocess

while True:
    with open('/var/log/syslog') as f:
        # Get the last line of the log file
        for line in f:
            pass
        last_line = line.rstrip()
        print(last_line)
        # Wait some time for a new log entry to be entered
        print("Sleeping for 30s...\n")
        time.sleep(30)

        # Now check if the new last line of the file matches what it did before
        # If it does not, check to see if the driver has failed
        for new_line in f:
            new_line = new_line.rstrip()
            if new_line == last_line:
                # No new entries
                pass
            else:
                # We have new log entries.  Check for driver errors.
                if 'Driver not connected' in new_line or 'Data stale' in new_line:
                    bash_command = "upsdrvctl start"
                    process = subprocess.Popen(bash_command.split(), stdout=subprocess.PIPE)
                    output, error = process.communicate()
                    print(f'Output: {output} \nError: {error}')
                    print("[!] Restarting driver... Please wait...")
                    time.sleep(30)
                    print("[!] Driver has been restarted!\n")
Reply
#2
You should take a look at watchdog. https://pypi.org/project/watchdog/

I think your loop is wrong. You don't want to re-read the file. You could open the file once for reading and leave it open.
from time import sleep

with open("output.txt", "r") as file:
    for last_line in file:
        pass
    while True:
        sleep(30)
        for new_line in file:
            if 'Driver not connected' in new_line or 'Data stale' in new_line:
                restart_the_driver
Or you could keep track of the end of file.
from time import sleep

# Get pointer to end of file
with open("output.txt", "a") as file:
    fp = file.tell()

while True:
    sleep(10)
    with open("output.txt", "r") as file:
        file.seek(fp)
        for line in file:
            if 'Driver not connected' in line or 'Data stale' in line:
                start_the_driver
        fp = file.tell()
droidus likes this post
Reply
#3
(Jun-10-2023, 08:53 PM)deanhystad Wrote: You should take a look at watchdog. https://pypi.org/project/watchdog/

I think your loop is wrong. You don't want to re-read the file. You could open the file once for reading and leave it open.
from time import sleep

with open("output.txt", "r") as file:
    for last_line in file:
        pass
    while True:
        sleep(30)
        for new_line in file:
            if 'Driver not connected' in new_line or 'Data stale' in new_line:
                restart_the_driver

I tried the first solution you provided, and it seems to do the same thing. Here's the last lines from the log file before it checks the file again:
"Jun 10 19:40:44 NUT usbhid-ups[26447]: libusb_get_interrupt: error submitting URB: Device or resource busy
Jun 10 19:40:44 NUT usbhid-ups[26447]: Got disconnected by another driver: Device or resource busy
Jun 10 19:40:44 NUT kernel: [369560.918282] usb 1-1.5: usbfs: process 26447 (usbhid-ups) did not claim interface 0 before use
Jun 10 19:40:44 NUT usbhid-ups[26411]: Signal 15: exiting"

Note: This is normal activity, and is fine. These messages can be safely ignored.

It gets stuck in this cycle where it just keeps re-starting the driver again.

Opening the file as such, will that take into account new log entries that are appended to the file?
Reply
#4
That's odd. I ran this program:
with open("output.txt", "r") as file:
    for last_line in file:
        pass
    while True:
        for new_line in file:
            if 'Driver not connected' in new_line or 'Data stale' in new_line:
                print("Starting the driver")
Then I opened the file "output.txt", typed 'Driver not connected', and saved the file. The program promptly prints "Starting the driver" one time. I wait a while to see if this is printed again. It does not. Only once. So I append 'Driver not connected' to the output.txt and save the file. The program promptly prints "Starting the driver" one time.

I get the same behavior if I run this program.
# Get pointer to end of file
with open("output.txt", "a") as file:
    fp = file.tell()
 
while True:
    with open("output.txt", "r") as file:
        file.seek(fp)
        for line in file:
            if 'Driver not connected' in line or 'Data stale' in line:
                print("Starting the driver")
            fp += len(line)
Each program only prints the line once when I add a line to the file. What happens if you run the program on your computer? Does it behave the same?
Reply
#5
You can also replace
for last_line in file:
    pass
with
import io
file.seek(0, io.SEEK_END) # go directly to the end of the file
Reply
#6
(Jun-11-2023, 09:28 AM)Gribouillis Wrote: You can also replace
for last_line in file:
    pass
with
import io
file.seek(0, io.SEEK_END) # go directly to the end of the file

Thank you for this, it worked! For some reason, the other one was not pulling the newest line file, and the variable was never getting updated. Over, and over, and over again, new_line was set to: "[!] This is the line that was checked for error: Jun 11 06:46:35 NUT upsmon[516]: Poll UPS [apc1500@localhost] failed - Driver not connected" even though that was not the most recent entry, and things were now working fine.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020