From 5b7f404842e38196b848b27980b1c8dae8ec12f0 Mon Sep 17 00:00:00 2001 From: Kye Date: Wed, 24 Jan 2024 12:44:25 -0500 Subject: [PATCH] [FEAT][Telemetry] --- playground/structs/sequential_workflow.py | 6 +- swarms/__init__.py | 12 +++ swarms/models/vip_llava.py | 2 +- swarms/telemetry/__init__.py | 8 +- swarms/telemetry/main.py | 58 ++++++++++++++ swarms/telemetry/sys_info.py | 95 +++++------------------ swarms/telemetry/user_utils.py | 28 ++++++- swarms/utils/__init__.py | 3 + swarms/utils/agent_ops_wrapper.py | 45 ----------- swarms/utils/save_logs.py | 46 +++++++++++ 10 files changed, 174 insertions(+), 129 deletions(-) create mode 100644 swarms/telemetry/main.py delete mode 100644 swarms/utils/agent_ops_wrapper.py create mode 100644 swarms/utils/save_logs.py diff --git a/playground/structs/sequential_workflow.py b/playground/structs/sequential_workflow.py index 5f60db72..7fa110bc 100644 --- a/playground/structs/sequential_workflow.py +++ b/playground/structs/sequential_workflow.py @@ -43,6 +43,6 @@ workflow.add(tasks=[task1, task2]) # Run the workflow workflow.run() -# Output the results -for task in workflow.tasks: - print(f"Task: {task.description}, Result: {task.result}") +# # Output the results +# for task in workflow.tasks: +# print(f"Task: {task.description}, Result: {task.result}") diff --git a/swarms/__init__.py b/swarms/__init__.py index 4e6785cb..54a60596 100644 --- a/swarms/__init__.py +++ b/swarms/__init__.py @@ -1,3 +1,4 @@ +# from swarms.telemetry.main import Telemetry # noqa: E402, F403 from swarms.telemetry.bootup import bootup # noqa: E402, F403 bootup() @@ -8,3 +9,14 @@ from swarms.models import * # noqa: E402, F403 from swarms.telemetry import * # noqa: E402, F403 from swarms.utils import * # noqa: E402, F403 from swarms.prompts import * # noqa: E402, F403 + + +# telemetry = Telemetry('mongodb://localhost:27017/', 'mydatabase') + +# telemetry.log_import('swarms.telemetry.bootup') +# telemetry.log_import('swarms.agents') +# telemetry.log_import('swarms.structs') +# telemetry.log_import('swarms.models') +# telemetry.log_import('swarms.telemetry') +# telemetry.log_import('swarms.utils') +# telemetry.log_import('swarms.prompts') diff --git a/swarms/models/vip_llava.py b/swarms/models/vip_llava.py index 31726275..db532913 100644 --- a/swarms/models/vip_llava.py +++ b/swarms/models/vip_llava.py @@ -2,7 +2,7 @@ from io import BytesIO import requests import torch -from PIl import Image +from PIL import Image from transformers import ( AutoProcessor, VipLlavaForConditionalGeneration, diff --git a/swarms/telemetry/__init__.py b/swarms/telemetry/__init__.py index 0a16ca28..d829b724 100644 --- a/swarms/telemetry/__init__.py +++ b/swarms/telemetry/__init__.py @@ -1,13 +1,12 @@ from swarms.telemetry.log_all import log_all_calls, log_calls from swarms.telemetry.sys_info import ( get_cpu_info, - get_oi_version, + get_swarms_verison, get_os_version, get_package_mismatches, get_pip_version, get_python_version, get_ram_info, - interpreter_info, system_info, ) from swarms.telemetry.user_utils import ( @@ -15,6 +14,7 @@ from swarms.telemetry.user_utils import ( generate_user_id, get_machine_id, get_system_info, + get_user_device_data, ) __all__ = [ @@ -26,11 +26,11 @@ __all__ = [ "generate_unique_identifier", "get_python_version", "get_pip_version", - "get_oi_version", + "get_swarms_verison", "get_os_version", "get_cpu_info", "get_ram_info", "get_package_mismatches", - "interpreter_info", "system_info", + "get_user_device_data", ] diff --git a/swarms/telemetry/main.py b/swarms/telemetry/main.py new file mode 100644 index 00000000..fe00fecf --- /dev/null +++ b/swarms/telemetry/main.py @@ -0,0 +1,58 @@ +import logging +import pymongo +import platform +import datetime + + +class Telemetry: + def __init__(self, db_url, db_name): + self.logger = self.setup_logging() + self.db = self.setup_db(db_url, db_name) + + def setup_logging(self): + logger = logging.getLogger("telemetry") + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + handler.setFormatter( + logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) + ) + logger.addHandler(handler) + return logger + + def setup_db(self, db_url, db_name): + client = pymongo.MongoClient(db_url) + return client[db_name] + + def capture_device_data(self): + data = { + "system": platform.system(), + "node": platform.node(), + "release": platform.release(), + "version": platform.version(), + "machine": platform.machine(), + "processor": platform.processor(), + "time": datetime.datetime.now(), + } + return data + + def send_to_db(self, collection_name, data): + collection = self.db[collection_name] + collection.insert_one(data) + + def log_and_capture(self, message, level, collection_name): + if level == "info": + self.logger.info(message) + elif level == "error": + self.logger.error(message) + data = self.capture_device_data() + data["log"] = message + self.send_to_db(collection_name, data) + + def log_import(self, module_name): + self.logger.info(f"Importing module {module_name}") + module = __import__(module_name, fromlist=["*"]) + for k in dir(module): + if not k.startswith("__"): + self.logger.info(f"Imported {k} from {module_name}") diff --git a/swarms/telemetry/sys_info.py b/swarms/telemetry/sys_info.py index 08ad1db3..d2841585 100644 --- a/swarms/telemetry/sys_info.py +++ b/swarms/telemetry/sys_info.py @@ -22,20 +22,20 @@ def get_pip_version(): return pip_version -def get_oi_version(): +def get_swarms_verison(): try: - oi_version_cmd = ( - subprocess.check_output(["interpreter", "--version"]) + swarms_verison_cmd = ( + subprocess.check_output(["swarms", "--version"]) .decode() .split()[1] ) except Exception as e: - oi_version_cmd = str(e) - oi_version_pkg = pkg_resources.get_distribution( - "open-interpreter" + swarms_verison_cmd = str(e) + swarms_verison_pkg = pkg_resources.get_distribution( + "swarms" ).version - oi_version = oi_version_cmd, oi_version_pkg - return oi_version + swarms_verison = swarms_verison_cmd, swarms_verison_pkg + return swarms_verison def get_os_version(): @@ -89,70 +89,15 @@ def get_package_mismatches(file_path="pyproject.toml"): return "\n" + "\n".join(mismatches) -def interpreter_info(interpreter): - try: - if interpreter.offline and interpreter.llm.api_base: - try: - curl = subprocess.check_output( - f"curl {interpreter.llm.api_base}" - ) - except Exception as e: - curl = str(e) - else: - curl = "Not local" - - messages_to_display = [] - for message in interpreter.messages: - message = message.copy() - try: - if len(message["content"]) > 600: - message["content"] = ( - message["content"][:300] - + "..." - + message["content"][-300:] - ) - except Exception as e: - print(str(e), "for message:", message) - messages_to_display.append(message) - - return f""" - - # Interpreter Info - - Vision: {interpreter.llm.supports_vision} - Model: {interpreter.llm.model} - Function calling: {interpreter.llm.supports_functions} - Context window: {interpreter.llm.context_window} - Max tokens: {interpreter.llm.max_tokens} - - Auto run: {interpreter.auto_run} - API base: {interpreter.llm.api_base} - Offline: {interpreter.offline} - - Curl output: {curl} - - # Messages - - System Message: {interpreter.system_message} - - """ + "\n\n".join([str(m) for m in messages_to_display]) - except: - return "Error, couldn't get interpreter info" - - -def system_info(interpreter): - oi_version = get_oi_version() - print(f""" - Python Version: {get_python_version()} - Pip Version: {get_pip_version()} - Open-interpreter Version: cmd:{oi_version[0]}, pkg: {oi_version[1]} - OS Version and Architecture: {get_os_version()} - CPU Info: {get_cpu_info()} - RAM Info: {get_ram_info()} - {interpreter_info(interpreter)} - """) - - # Removed the following, as it causes `FileNotFoundError: [Errno 2] No such file or directory: 'pyproject.toml'`` on prod - # (i think it works on dev, but on prod the pyproject.toml will not be in the cwd. might not be accessible at all) - # Package Version Mismatches: - # {get_package_mismatches()} + +def system_info(): + swarms_verison = get_swarms_verison() + return { + "Python Version": get_python_version(), + "Pip Version": get_pip_version(), + "Swarms Version": swarms_verison, + "OS Version and Architecture": get_os_version(), + "CPU Info": get_cpu_info(), + "RAM Info": get_ram_info(), + } + diff --git a/swarms/telemetry/user_utils.py b/swarms/telemetry/user_utils.py index 74667326..9369bc26 100644 --- a/swarms/telemetry/user_utils.py +++ b/swarms/telemetry/user_utils.py @@ -2,7 +2,8 @@ import hashlib import platform import uuid import socket - +from swarms.telemetry.sys_info import system_info +from swarms.telemetry.check_update import check_for_package # Helper functions def generate_user_id(): @@ -47,6 +48,7 @@ def get_system_info(): ), "processor": platform.processor(), "python_version": platform.python_version(), + "Misc": system_info(), } return info @@ -61,3 +63,27 @@ def generate_unique_identifier(): system_info = get_system_info() unique_id = uuid.uuid5(uuid.NAMESPACE_DNS, str(system_info)) return str(unique_id) + + +def get_local_ip(): + """Get local ip + + Returns: + str: local ip + + """ + return socket.gethostbyname(socket.gethostname()) + + + +def get_user_device_data(): + data = { + "ID": generate_user_id(), + "Machine ID": get_machine_id(), + "System Info": get_system_info(), + "UniqueID": generate_unique_identifier(), + "Swarms [Version]": check_for_package("swarms"), + } + return data + +# \ No newline at end of file diff --git a/swarms/utils/__init__.py b/swarms/utils/__init__.py index de8ffb57..df9fe6ca 100644 --- a/swarms/utils/__init__.py +++ b/swarms/utils/__init__.py @@ -22,6 +22,8 @@ from swarms.utils.try_except_wrapper import try_except_wrapper from swarms.utils.download_weights_from_url import ( download_weights_from_url, ) +from swarms.utils.save_logs import parse_log_file + __all__ = [ "SubprocessCodeInterpreter", @@ -42,4 +44,5 @@ __all__ = [ "data_to_text", "try_except_wrapper", "download_weights_from_url", + "parse_log_file", ] diff --git a/swarms/utils/agent_ops_wrapper.py b/swarms/utils/agent_ops_wrapper.py deleted file mode 100644 index c1a019d2..00000000 --- a/swarms/utils/agent_ops_wrapper.py +++ /dev/null @@ -1,45 +0,0 @@ -import logging -import agentops - -class AgentOpsWrapper: - """ - A wrapper for the AgentOps client that adds error handling and logging. - """ - - def __init__(self, api_key): - """ - Initialize the AgentOps client with the given API key. - """ - self.client = agentops.Client(api_key) - self.logger = logging.getLogger(__name__) - self.logger.setLevel(logging.INFO) - - def record_action(self, action_name): - """ - Record an action with the given name. - """ - def decorator(func): - def wrapper(*args, **kwargs): - try: - self.client.record_action(action_name) - result = func(*args, **kwargs) - self.logger.info(f"Action {action_name} completed successfully.") - return result - except Exception as e: - self.logger.error(f"Error while recording action {action_name}: {e}") - raise - return wrapper - return decorator - - def end_session(self, status): - """ - End the session with the given status. - """ - try: - self.client.end_session(status) - self.logger.info(f"Session ended with status {status}.") - except Exception as e: - self.logger.error(f"Error while ending session: {e}") - raise - -# agentops = AgentOpsWrapper(api_key) \ No newline at end of file diff --git a/swarms/utils/save_logs.py b/swarms/utils/save_logs.py new file mode 100644 index 00000000..c8193905 --- /dev/null +++ b/swarms/utils/save_logs.py @@ -0,0 +1,46 @@ +import os + + +def parse_log_file(filename: str): + """ + Parse a log file and return a list of log entries. + + Each log entry is a dictionary with keys for the timestamp, name, level, and message. + + Args: + filename (str): The name of the log file. + + Returns: + list: A list of log entries. + + Raises: + FileNotFoundError: If the log file does not exist. + ValueError: If a log entry does not have the correct format. + """ + # Check if the file exists + if not os.path.exists(filename): + raise FileNotFoundError( + f"The file {filename} does not exist." + ) + + log_entries = [] + + with open(filename, "r") as file: + for line in file: + parts = line.split(" - ") + # Check if the log entry has the correct format + if len(parts) != 4: + raise ValueError( + f"The log entry '{line}' does not have the" + " correct format." + ) + timestamp, name, level, message = parts + log_entry = { + "timestamp": timestamp, + "name": name, + "level": level, + "message": message.rstrip("\n"), + } + log_entries.append(log_entry) + + return log_entries