Windows task scheduler and python logging module - python

I have a program which is running on daily basis. I would like to have a log created for each run of it. Here is the snip of code responsible for logging:
logging.basicConfig(filename = 'log.txt', level = logging.DEBUG, format = '%(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program') # example logging
Everything runs perfectly fine as long as I launch it by .py file or .bat file (mouse clicking in file explorer). Unfortunately, when I put it on the schedule the program runs fine but log file doesn't get created.
I have tried multiple scheduler settings but the problem seems to be located in the code of the script.
Thanks for feedback!

I wanted to add the solution as an answer too, since this seems to be a somewhat common problem which has caused me some grief in the past.
When executing something from the Windows Task Scheduler the working directory of that process is not by default the path of the executable but some other directory. E.g. when your Scheduler action calls C:\sample.py this is not executed in C:\ but C:\Windows\system32 (in my case).
You can verify this by adding a Scheduled Task calling a simple Python/Batch script which saves the active working directory to some file, such as this
import os
with open("C:\\cwd.txt", "w") as fh:
fh.write(os.getcwd())
or this
echo %cd% >> C:\cwd.txt
This messes with any relative paths your program may contain and, I suspect, it has some more subtle issues that I have not been able to pin down yet.
Problems can be avoided by explicitly setting the optional 'Start in' path for your action:

Related

python logging: Any way to recreate log file while running when the opened file being deleted?

The code snippet is as follows:
import logging
import time
logging.basicConfig(filename='test.log', filemode='a', format='...', datefmt='...', level=logging.INFO)
for i in range(0, 1000):
time.sleep(1)
logging.info('...')
After executing this python file, test.log is created as expected, yet when I delete this file while the python file is still running, test.log could not be recreate again as if it is writing to /dev/null later on.
Is there any way to detect the file being deleted and recreate test.log again from logging module? Thanks~
Assuming an UNIX platform, it's not writing "as if to /dev/null", it's writing to that same test.log on disk (yes, with the implication that you could run out of disk space!).
You might know the actual name for a delete operation is unlink; indeed, if you "delete" the file, you just unlink the name from the directory it's in.
As soon as the Python process closes the file descriptor (i.e. there are no more remaining references to the file) it'll actually be gone. (You can actually use tools such as lsof or the /dev/.../fd hierarchy to recover and re-link the file if you need to so long as it's still open.)
Anyway, to answer your question: instead of basicConfiging your logger, use logging.handlers.WatchedFileHandler:
The WatchedFileHandler class, located in the logging.handlers module, is a FileHandler which watches the file it is logging to. If the file changes, it is closed and reopened using the file name.

Use Robot Framework logging file at the end of test case execution

I am a new Robot Framework user and have a question regarding the log file that it makes at the end of executing testcases. I would like to use the html file it creates and upload it automatically to the correct ticket. I already have python code that works to upload the file and it can be used as a keyword, but I am not sure how I can call upon that keyword as a test teardown step as at that point the logging probably is not created yet..
Is this correct and if so: is there another way to automatically call a python function to upload the html file after executing a testcase?
Yes, you can use things as below:
Test Teardown Run keyword if test Passed/Failed Name_of_kw
Add this to your settings section of .robot file.
Now, define the kw: (Import Process Library first in your robot file)
Name_of_kw
Start Process <tab> python <tab> path_to_file.py<tab> alias=prog
Wait for Process prog #wait until it gets completed
Get Process Result prog stdout=yes #to make sure you have uploaded it
================
more details at -https://robotframework.org/robotframework/latest/libraries/Process.html#library-documentation-top
I've been facing the same problem and I've got an alternative solution for getting log files (log.html, report.html, output.xml) in same execution and upload them to a FTP Server.
I created a python script in Robot Framework's root project folder:
import subprocess
import os.path
import time
arguments = sys.argv
subprocess.run(arguments)
logs = ['log.html', 'report.html', 'output.xml']
while not os.path.exists(logs[0] and logs[1] and logs[2]):
time.sleep(1)
do_something()
Instead of running:
robot .\tests\...\suite
Run:
python script.py robot .\tests\...\suite
In that way, you will be able to work with output files when tests or suites are finished.
If you run robot's command with -d flag to save results on a different folder, consider using automatic variable from Robot Framework called ${OUTPUT DIR} to get full source path and save it to txt file on root folder. That's because you'll be able to read it and find the logs in your script.py.

How do I change permissions on rolling python log files without calling os.chmod over and over?

I'm working with the Python logging configuration below
import logging
import os
#Setup logging
logger = logging.getLogger('/logs/some-log')
logger.setLevel(logging.INFO)
handler = RotatingFileHandler('./logs/some-log.log', maxBytes=10240, backupCount=5)
logger.addHandler(handler)
#End Logging
#Set Logging Permissions
os.chmod('/logs/some*.log', 0o755)
#End Set Logging Permissions
I have a rolling log of 5 files. Let's say this program kicks off for the first time and there is just one log file. It's fine. The permissions are set at the start of the application.
However, this code is at the beginning of an application that's started once a month. I don't think some-log1.log, some-log2.log, some-log3.log etc will have their permissions set correctly when they are generated because the chmod command only runs at the start of the application.
I don't want to put the chmod command in my main program loop because it will run every 30 seconds. I also don't want to make some other timer just for this one command which would cause me to maybe have access to the new file depending on when it's generated.
Is there a way to set permissions to the log file in the python logging library? Is there a better way to code this?

Batch file not running python script in task scheduler

I have a scraping python script and a batch file that when run from CMD works perfectly however when I try to run it from Task Scheduler nothing happens.
I know there are a lot of questions regarding the same issue but I have tried all of the proposed answers and non of them seem to work.
Don't know if this is relevant but script would open Firefox and scrape some websites.
Have tried adding full permissions to the folders and files that I am using.
Also, have tried in Task Scheduler to set up "Run wheter user is logged on or not", "Run with highest privileges" , "Start in (optional): add/bactch/file/path" and so on
Batch file:
py "C:\python_test\myscript.py"
It should run the python script which opens Firefox and scrapes some websites, gets their links and saves them in a csv file
Here is myscript.py:
import datetime
import time
import csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import os
file_path = r"C:\General\{0:%Y%m%d}\results{0:%Y%m%d%H%M%S}.csv".format(datetime.datetime.now())
directory = os.path.dirname(file_path)
try:
os.stat(directory)
except:
os.mkdir(directory)
from bs4 import BeautifulSoup
def init_driver():
caps = DesiredCapabilities.FIREFOX
caps['marionette'] = True
driver = webdriver.Firefox(capabilities=caps)
driver.wait = WebDriverWait(driver, 15)
return driver
xpath = {
'english': '//*[#id="xxx"]',
'soort': '//*[#id="xxx"]/option[text()=\'|- Announcement of change in denominator or in thresholds\']',
'start': '//*[#id="xxx"]',
'end': '//*[#id="xxx"]',
'submit': '//*[#id="xxx"]',
'pub_sort': '//*[#id="xxx"]',
}
if __name__ == "__main__":
driver = init_driver()
try:
driver.get("http://SOMEWEBSITE")
driver.find_element_by_css_selector('[id$=hplEnglish]').click()
except Exception:
DoNothing = ""
time.sleep(2)
driver.find_element_by_css_selector('[id$=hplEnglish]').click()
time.sleep(3)
#alert_obj = driver.switch_to.alert
#alert_obj.dismiss()
#driver.find_element_by_xpath(xpath['english']).click()
today = datetime.datetime.now()
driver.wait.until(EC.element_to_be_clickable((By.XPATH, xpath['soort']))).click()
driver.find_element_by_xpath(xpath['start']).send_keys((today-datetime.timedelta(weeks=1)).strftime('%d/%m/%Y'))
driver.find_element_by_xpath(xpath['end']).send_keys(today.strftime('%d/%m/%Y'))
driver.find_element_by_xpath(xpath['submit']).click()
for i in range(2):
driver.wait.until(EC.element_to_be_clickable((By.XPATH, xpath['pub_sort']))).click()
time.sleep(5)
html = driver.page_source
driver.quit()
results = BeautifulSoup(html, 'html.parser').find('div', { 'id': 'SearchResults'}).table
res = [['issuer', 'type', 'date']]
for x in results.find_all('tr')[1:]:
# print(x.text.strip())
try:
a, b, c = [i.text.strip() for i in x.find_all('td', class_='resultItemTop')[:3]]
res.append([a,b,c])
except ValueError:
continue
with open(file_path, 'w', newline='') as result:
writer = csv.writer(result, delimiter=',')
writer.writerows(res)
print('finished')
Introduction
I suggest to read first What must be taken into account on executing a batch file as scheduled task?
Issue 1: Current directory
The first issue here is most likely the current directory on running the batch file.
Windows sets the directory of the batch file as current directory on double clicking a batch file, except the batch file path is a UNC path starting with \\computername\share\.
The current directory for a scheduled task is by default %SystemRoot%\System32, i.e. the Windows system directory which of course is special protected against modifications. Many batch files expect that the current directory is the directory of the batch file and not any other directory.
Solution 1: Define Start in directory in properties of scheduled task.
Start Windows Task Scheduler.
Navigate to the task and double click on it to open the Properties of the task.
Select tab Action and click on button Edit.
There is Start in (optional). Enter here the path of the executed batch file.
Click two times on button OK to save this important modification in properties.
Solution 2: Make batch file directory the current directory using CD.
In the batch file insert after first line being usually #echo off the line:
cd /D "%~dp0"
This command line changes the current directory from default %SystemRoot%\System32 to the directory of the batch file as long as the batch file is not started using a UNC path.
Open a command prompt window and run cd /? for help on command CD and option /D.
Solution 3: Make batch file directory the current directory using PUSHD.
This solution is best if the batch file is stored on a network resource accessed using UNC path and of course the scheduled task is configured to run with credentials (user account and password) with permissions to read content of the batch file on the network resource.
In the batch file insert after first line being usually #echo off the lines:
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0"
The batch file should additionally contain as last two line executed before exiting batch file processing the two lines:
popd
endlocal
Open a command prompt window and run pushd /?, popd /?, setlocal /? and endlocal /? for help on these four commands and read also this answer for even more details on these four commands.
Solution 4: Code everything to be independent on current directory.
The fourth solution is writing batch file and Python script for being independent on which directory is the current directory on execution of batch file and Python script.
This solution requires that all files and directories are specified with full qualified file/folder name which means full path + file/folder name + file extension.
The full file/folder paths can be derived from known paths on execution like path of the batch file which can be referenced with %~dp0 inside the batch file and which expands to a path string always ending with backslash which means it can be concatenated with file/folder names without usage of an additional backslash.
See also Wikipedia article about Windows Environment Variables.
Issue 2: Environment variables
Scheduled tasks are often executed with built-in local system account. So all environment variables defined just for the user account used on developing and testing the batch file either are not defined at all or are defined different.
Open from Windows Control Panel from item System the Advanced system settings or press key combination Win+Break if keyboard has a key Break (often as alternate function requiring pressing additionally the key Fn) and clicking next on Advanced system settings on left side. The System Properties dialog is opened wit tab Advanced selected containing at bottom the button Environment Variables... which must be clicked to open the Environment Variables window.
There are two lists of environment variables: User variables for ... and System variables. The system variables are defined for all accounts including built-in local system account. The user variables are defined only for the displayed user.
The user variables defined for current user are important and could be a reason why a batch file executed with a double click by current user works, but does not work on being executed as scheduled task with built-in system account. A user PATH is often a main source of not working batch file on execution as scheduled task if the used scripts and executables depend on specific folder paths in local PATH defined in user PATH.
Please take a look on What is the reason for "X is not recognized as an internal or external command, operable program or batch file"? for more information about system, user and local PATH and environment variable PATHEXT used on writing in a batch file just py instead of the script/executable file with full qualified file name.
So it is definitely better to use
"C:\Python27\python.exe" "C:\python_test\myscript.py"
instead of using
py "C:\python_test\myscript.py"
which results in cmd.exe searching around for a file py using local PATHEXT and local PATH environment variables which can file if the folder containing file py is defined in user PATH.
I have not installed Python and so don't know what py really is. It could be a batch file with file name py.cmd or py.bat in which case the command CALL must be used if the batch file contains additional command lines after the command line with py and which perhaps depends on user environment variables. It could be a symbolic link to python.exe in installation folder of Python. I don't know.
Issue 3: Network resources
Many scheduled tasks access files, folders or data via a network. In this case the scheduled task must be configured to run with the credentials (user account and password) which has the required permissions to access the files, folders or data on the network resource. The usage of the built-in local system account is in this case nearly never the right choice to run the scheduled task because of local system account has usually no permissions to read/write data on any network resource.
Conclusion
It is good practice in my opinion to write a batch file being executed as scheduled task to be as independent as possible on other batch files and environment variables not defined in the batch file executed by Windows task scheduler itself. A design with dependencies on other script files and variables defined outside main script cause often sooner or later (sometimes years later) unexpected execution problems.
The programmer of a script written for execution as scheduled task should really know very well on which files, libraries, environment variables and registry keys/values the script and called executables depend on to work properly.
A batch file containing only one line to execute one application with some parameters is completely unnecessary and just a potential source of not working scheduled task because of the executable to run and its parameters can be in this case also directly set in properties of the scheduled task. There is absolutely no need to run %SystemRoot%\System32\cmd.exe with implicit option /C to process a specified batch file containing only one command line to execute an application with zero or more parameters because of Windows task scheduler can directly run the application with its parameters, too.

Python task scheduler file input and output 0x2

I've got a process I'm trying to automate through the Windows task scheduler. The file is located right next to the script on a subfolder in my desktop. A mockup that shows the problem I'm running into is:
import os
if __name__ == "__main__":
lines = []
with open(r'C:\Users\user\Desktop\folder\config.txt') as file:
for line in file:
lines.append(line)
with open(r'C:\Users\user\Desktop\folder\output.txt', 'w') as file:
for line in lines:
file.write(line)
When I run this through the command line, the code works fine. The config file is read in properly and the output works properly.
However, in task scheduler, the program fails to execute with an 0x2 error code. In task scheduler, I have the tried with the following task scheduler options selected:
Run only when user is logged on/Run with highest priveledges Run only
when user is logged on/Highest priveledges not checked Run whether
user is logged on or not/Run with highest priveledges Run whether
user is logged on or not/Highest priveledges not checked
I am using absolute paths - as you can see in the above example. I'm also using the "start in" option inside of task scheduler.
This is seriously annoying me.
Edit: I am using absolute paths inside of task scheduler to both the Python executable and the script.

Categories