Updated
This commit is contained in:
231
Scripts/TaskReporter.py
Normal file
231
Scripts/TaskReporter.py
Normal file
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TaskReporter - Task Reporting Tool
|
||||
|
||||
This script is designed to record and track user task execution. It sends task information
|
||||
(including username, tool name, task name, time saved, time cost) to a specified server for statistics.
|
||||
|
||||
Usage:
|
||||
|
||||
#---------------------------------- usage 1: decorator ----------------------------------
|
||||
from TaskReporter import task_reporter_decorator
|
||||
|
||||
debug_mode = True
|
||||
|
||||
@task_reporter_decorator(tool_name='MetaBox', task_name='CheckUV', debug=debug_mode, time_saved=5)
|
||||
def your_function():
|
||||
# your code
|
||||
|
||||
#---------------------------------- usage 2: function ----------------------------------
|
||||
from TaskReporter import task_reporter
|
||||
|
||||
debug_mode = True
|
||||
|
||||
def your_function():
|
||||
start_time = time.time()
|
||||
# your function code
|
||||
task_reporter(tool_name='MetaBox', task_name='CheckUV', debug=debug_mode, time_saved=5, time_cost=round(time.time()-start_time, 3))
|
||||
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from functools import wraps
|
||||
import time, datetime, json
|
||||
|
||||
# add lib path to import requests
|
||||
py_version = sys.version_info.major
|
||||
minor_version = sys.version_info.minor
|
||||
version = "py{}{}".format(py_version, minor_version) if py_version in [2,3] and minor_version<=7 else "py38+"
|
||||
lib_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "reporter_lib", version)
|
||||
if lib_path not in sys.path:
|
||||
sys.path.append(lib_path)
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
from requests.packages.urllib3.util.retry import Retry
|
||||
|
||||
|
||||
class TaskReporter:
|
||||
def __init__(self):
|
||||
self.session = requests.Session()
|
||||
self.session.mount('http://', HTTPAdapter(max_retries=3))
|
||||
self.session.mount('https://', HTTPAdapter(max_retries=3))
|
||||
self.server_status = {'available': True, 'last_check': 0}
|
||||
self.SERVER_URL = 'https://toolstrack.cgnico.com'
|
||||
self.cache_file = os.path.join(os.environ.get('APPDATA'), 'task_cache.json')
|
||||
|
||||
def report_task(self, data, is_cached_task=False):
|
||||
# first check and send cached data
|
||||
if not is_cached_task:
|
||||
self._try_send_cached_tasks()
|
||||
|
||||
task_has_cached = False
|
||||
|
||||
current_time = time.time()
|
||||
if not self.server_status['available'] and not is_cached_task:
|
||||
if current_time - self.server_status['last_check'] < 10:
|
||||
self._cache_task(data)
|
||||
return False
|
||||
|
||||
try:
|
||||
response = self.session.post(
|
||||
'{}/api.php'.format(self.SERVER_URL),
|
||||
json=data,
|
||||
timeout=1
|
||||
)
|
||||
self.server_status['available'] = True
|
||||
print(response.json())
|
||||
return response.json()
|
||||
except (requests.exceptions.RequestException, TimeoutError) as e:
|
||||
self.server_status['available'] = False
|
||||
self.server_status['last_check'] = current_time
|
||||
if not task_has_cached and not is_cached_task: self._cache_task(data)
|
||||
task_has_cached = True
|
||||
print("Failed to connect to server, task has been cached\n{}".format(str(e)))
|
||||
# print("Failed to connect to server: {}".format(str(e)))
|
||||
return False
|
||||
|
||||
def _cache_task(self, data):
|
||||
try:
|
||||
data['timestamp'] = (datetime.datetime.utcnow() + datetime.timedelta(hours=8)).isoformat()
|
||||
|
||||
cache = self._read_cache()
|
||||
cache.append(data)
|
||||
|
||||
with open(self.cache_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(cache, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# print("Task cached: {}".format(self.cache_file))
|
||||
except Exception as e:
|
||||
print("Cache task failed:{}".format(str(e)))
|
||||
|
||||
def _read_cache(self):
|
||||
try:
|
||||
if os.path.exists(self.cache_file):
|
||||
with open(self.cache_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
return []
|
||||
except Exception as e:
|
||||
print("Read cache failed: {}".format(str(e)))
|
||||
return []
|
||||
|
||||
def _try_send_cached_tasks(self):
|
||||
if not os.path.exists(self.cache_file):
|
||||
return
|
||||
|
||||
cache = self._read_cache()
|
||||
if not cache:
|
||||
return
|
||||
|
||||
# print("Find {} cached tasks, try to send again...".format(len(cache)))
|
||||
if not self.server_status['available']:
|
||||
return
|
||||
|
||||
successful_indices = []
|
||||
for i, task in enumerate(cache):
|
||||
try:
|
||||
response = self.report_task(task, is_cached_task=True)
|
||||
if response != False:
|
||||
successful_indices.append(i)
|
||||
print("Cached task sent successfully: {}".format(task.get('task_name')))
|
||||
else:
|
||||
# print("Cached task sent failed")
|
||||
break
|
||||
except Exception as e:
|
||||
print("Send cached task failed: {}".format(str(e)))
|
||||
break
|
||||
|
||||
if successful_indices:
|
||||
new_cache = [task for i, task in enumerate(cache) if i not in successful_indices]
|
||||
if new_cache:
|
||||
with open(self.cache_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_cache, f, ensure_ascii=False, indent=2)
|
||||
print("{} tasks left to send".format(len(new_cache)))
|
||||
else:
|
||||
os.remove(self.cache_file)
|
||||
print("All cached tasks sent")
|
||||
|
||||
reporter = TaskReporter()
|
||||
|
||||
def task_reporter_decorator(tool_name, task_name, debug=False, time_saved=0):
|
||||
"""
|
||||
task reporter decorator
|
||||
:param tool_name: name of the tool, eg "MetaBox"
|
||||
:param task_name: name of the task, eg "CheckUV"
|
||||
:param debug: set to True when develop, and set it to False when release the tool to artists
|
||||
:param time_saved: time saved for this task, usually should communicate with artists to get a reasonable value
|
||||
"""
|
||||
# reporter = TaskReporter()
|
||||
def run_and_report(func):
|
||||
@wraps(func)
|
||||
def execute_task(*args, **kwargs):
|
||||
# record start time
|
||||
start_time = time.time()
|
||||
|
||||
# execute original function
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
return result
|
||||
except Exception as e:
|
||||
raise e
|
||||
finally:
|
||||
# report task - 无论函数执行成功与否都发送报告
|
||||
success = result != False
|
||||
data= {
|
||||
'username': os.environ.get('USERNAME'),
|
||||
'tool_name': tool_name + "(Debug)" if debug else tool_name,
|
||||
'task_name': task_name,
|
||||
'time_saved': str(time_saved if success else 0), # 如果失败,节省时间为0
|
||||
'time_cost': str(round(time.time() - start_time, 3)), # 确保是字符串格式
|
||||
'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # 使用文档中指定的时间格式
|
||||
'status': "success" if success else "failed" # 添加状态字段
|
||||
}
|
||||
reporter.report_task(data)
|
||||
|
||||
return execute_task
|
||||
return run_and_report
|
||||
|
||||
def task_reporter(tool_name, task_name, debug=False, time_saved=0, time_cost=0):
|
||||
'''
|
||||
task reporter function
|
||||
:param tool_name: name of the tool, eg "MetaBox"
|
||||
:param task_name: name of the task, eg "CheckUV"
|
||||
:param debug: set to True when develop, and set it to False when release the tool to artists
|
||||
:param time_saved: time saved for this task, usually should communicate with artists to get a reasonable value
|
||||
:param time_cost: time cost for this task, you can get it from
|
||||
time_cost = round(time.time() - start_time, 3)
|
||||
'''
|
||||
# reporter = TaskReporter()
|
||||
data = {
|
||||
'username': os.environ.get('USERNAME'),
|
||||
'tool_name': tool_name + "(Debug)" if debug else tool_name,
|
||||
'task_name': task_name,
|
||||
'time_saved': str(time_saved), # 确保是字符串格式
|
||||
'time_cost': str(round(time_cost, 3)), # 确保是字符串格式
|
||||
'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 使用文档中指定的时间格式
|
||||
}
|
||||
reporter.report_task(data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#---------------------------------- usage 1: decorator ----------------------------------
|
||||
debug_mode = True
|
||||
@task_reporter_decorator(tool_name='MetaBox', task_name='CheckUV', debug=debug_mode, time_saved=5)
|
||||
def check_uv_dec():
|
||||
print("Check UV, and report by decorator")
|
||||
|
||||
#---------------------------------- usage 2: function ----------------------------------
|
||||
def check_uv_func():
|
||||
debug_mode = True
|
||||
start_time = time.time()
|
||||
|
||||
# function code
|
||||
print("Check UV, and report by function")
|
||||
|
||||
task_reporter(tool_name='MetaBox', task_name='CheckUV', debug=debug_mode, time_saved=5, time_cost=round(time.time()-start_time, 3))
|
||||
|
||||
check_uv_dec()
|
||||
check_uv_func()
|
||||
|
Reference in New Issue
Block a user