Merge pull request #58 from bucolucas/add-metrics-functionality
Add metrics functionality to GitHub and Log tools
This commit is contained in:
+26
-8
@@ -1,5 +1,6 @@
|
|||||||
# tools/github_tool.py
|
# tools/github_tool.py
|
||||||
from .base_tool import BaseTool
|
from .base_tool import BaseTool
|
||||||
|
from .metrics import metrics
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
import base64
|
import base64
|
||||||
@@ -313,6 +314,7 @@ class GitHubTool(BaseTool):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def execute(self, function_name, **kwargs):
|
def execute(self, function_name, **kwargs):
|
||||||
self.logger.info(f"Executing: {function_name}")
|
self.logger.info(f"Executing: {function_name}")
|
||||||
|
|
||||||
@@ -354,6 +356,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _read_file(self, path):
|
def _read_file(self, path):
|
||||||
self.logger.info(f"Reading file: {path} from branch: {self.current_branch}")
|
self.logger.info(f"Reading file: {path} from branch: {self.current_branch}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/contents/{path}"
|
url = f"{self.base_url}/repos/{self.repo}/contents/{path}"
|
||||||
@@ -368,6 +371,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _create_branch(self, branch_name, base_branch):
|
def _create_branch(self, branch_name, base_branch):
|
||||||
self.logger.info(f"Creating branch: {branch_name} from base: {base_branch}")
|
self.logger.info(f"Creating branch: {branch_name} from base: {base_branch}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/git/refs"
|
url = f"{self.base_url}/repos/{self.repo}/git/refs"
|
||||||
@@ -376,7 +380,7 @@ class GitHubTool(BaseTool):
|
|||||||
error_message = f"Error getting base branch: {response.status_code}"
|
error_message = f"Error getting base branch: {response.status_code}"
|
||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
sha = response.json()["object"]["sha"]
|
sha = response.json()["object"]["sha"]
|
||||||
data = {
|
data = {
|
||||||
"ref": f"refs/heads/{branch_name}",
|
"ref": f"refs/heads/{branch_name}",
|
||||||
@@ -393,33 +397,34 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _commit_file(self, file_path, content, commit_message):
|
def _commit_file(self, file_path, content, commit_message):
|
||||||
self.logger.info(f"Committing file: {file_path} to branch: {self.current_branch}")
|
self.logger.info(f"Committing file: {file_path} to branch: {self.current_branch}")
|
||||||
if self.current_branch == "main":
|
if self.current_branch == "main":
|
||||||
error_message = "Cannot commit directly to main branch"
|
error_message = "Cannot commit directly to main branch"
|
||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
|
url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
|
||||||
|
|
||||||
self.logger.info("Checking if file already exists")
|
self.logger.info("Checking if file already exists")
|
||||||
response = requests.get(url, headers=self.headers, params={"ref": self.current_branch})
|
response = requests.get(url, headers=self.headers, params={"ref": self.current_branch})
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"message": commit_message,
|
"message": commit_message,
|
||||||
"content": base64.b64encode(content.encode()).decode(),
|
"content": base64.b64encode(content.encode()).decode(),
|
||||||
"branch": self.current_branch
|
"branch": self.current_branch
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
self.logger.info("File exists, updating")
|
self.logger.info("File exists, updating")
|
||||||
file_sha = response.json()["sha"]
|
file_sha = response.json()["sha"]
|
||||||
data["sha"] = file_sha
|
data["sha"] = file_sha
|
||||||
else:
|
else:
|
||||||
self.logger.info("File does not exist, creating new file")
|
self.logger.info("File does not exist, creating new file")
|
||||||
|
|
||||||
response = requests.put(url, headers=self.headers, json=data)
|
response = requests.put(url, headers=self.headers, json=data)
|
||||||
|
|
||||||
if response.status_code in [200, 201]:
|
if response.status_code in [200, 201]:
|
||||||
success_message = f"File committed successfully to branch '{self.current_branch}'"
|
success_message = f"File committed successfully to branch '{self.current_branch}'"
|
||||||
self.logger.info(success_message)
|
self.logger.info(success_message)
|
||||||
@@ -429,6 +434,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _create_pull_request(self, title, body, base):
|
def _create_pull_request(self, title, body, base):
|
||||||
self.logger.info(f"Creating pull request: {title} from {self.current_branch} to {base}")
|
self.logger.info(f"Creating pull request: {title} from {self.current_branch} to {base}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/pulls"
|
url = f"{self.base_url}/repos/{self.repo}/pulls"
|
||||||
@@ -448,6 +454,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _get_branch_sha(self, branch):
|
def _get_branch_sha(self, branch):
|
||||||
url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch}"
|
url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch}"
|
||||||
response = requests.get(url, headers=self.headers)
|
response = requests.get(url, headers=self.headers)
|
||||||
@@ -456,6 +463,7 @@ class GitHubTool(BaseTool):
|
|||||||
else:
|
else:
|
||||||
return f"Error getting branch SHA: {response.status_code}"
|
return f"Error getting branch SHA: {response.status_code}"
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _list_files(self, path):
|
def _list_files(self, path):
|
||||||
self.logger.info(f"Listing files in: {path} on branch: {self.current_branch}")
|
self.logger.info(f"Listing files in: {path} on branch: {self.current_branch}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/contents/{path}"
|
url = f"{self.base_url}/repos/{self.repo}/contents/{path}"
|
||||||
@@ -470,6 +478,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _search_code(self, query):
|
def _search_code(self, query):
|
||||||
self.logger.info(f"Searching code with query: {query}")
|
self.logger.info(f"Searching code with query: {query}")
|
||||||
url = f"{self.base_url}/search/code"
|
url = f"{self.base_url}/search/code"
|
||||||
@@ -487,6 +496,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _get_commit_history(self, file_path, num_commits):
|
def _get_commit_history(self, file_path, num_commits):
|
||||||
self.logger.info(f"Getting commit history for file: {file_path}, number of commits: {num_commits}")
|
self.logger.info(f"Getting commit history for file: {file_path}, number of commits: {num_commits}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/commits"
|
url = f"{self.base_url}/repos/{self.repo}/commits"
|
||||||
@@ -504,15 +514,18 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _get_current_branch(self):
|
def _get_current_branch(self):
|
||||||
self.logger.info(f"Getting current branch: {self.current_branch}")
|
self.logger.info(f"Getting current branch: {self.current_branch}")
|
||||||
return self.current_branch
|
return self.current_branch
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _set_current_branch(self, branch_name):
|
def _set_current_branch(self, branch_name):
|
||||||
self.logger.info(f"Setting current branch from {self.current_branch} to {branch_name}")
|
self.logger.info(f"Setting current branch from {self.current_branch} to {branch_name}")
|
||||||
self.current_branch = branch_name
|
self.current_branch = branch_name
|
||||||
return f"Current branch set to: {self.current_branch}"
|
return f"Current branch set to: {self.current_branch}"
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _get_file_at_commit(self, file_path, commit_sha):
|
def _get_file_at_commit(self, file_path, commit_sha):
|
||||||
self.logger.info(f"Getting file: {file_path} at commit: {commit_sha}")
|
self.logger.info(f"Getting file: {file_path} at commit: {commit_sha}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
|
url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
|
||||||
@@ -527,6 +540,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _list_branches(self, per_page=100, all_pages=True):
|
def _list_branches(self, per_page=100, all_pages=True):
|
||||||
self.logger.info(f"Listing branches. Per page: {per_page}, All pages: {all_pages}")
|
self.logger.info(f"Listing branches. Per page: {per_page}, All pages: {all_pages}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/branches"
|
url = f"{self.base_url}/repos/{self.repo}/branches"
|
||||||
@@ -556,6 +570,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.info(f"Successfully listed all branches. Total: {len(all_branches)}")
|
self.logger.info(f"Successfully listed all branches. Total: {len(all_branches)}")
|
||||||
return all_branches
|
return all_branches
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _approve_pull_request(self, pull_number):
|
def _approve_pull_request(self, pull_number):
|
||||||
self.logger.info(f"Approving pull request: {pull_number}")
|
self.logger.info(f"Approving pull request: {pull_number}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/reviews"
|
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/reviews"
|
||||||
@@ -572,6 +587,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _close_pull_request(self, pull_number):
|
def _close_pull_request(self, pull_number):
|
||||||
self.logger.info(f"Closing pull request: {pull_number}")
|
self.logger.info(f"Closing pull request: {pull_number}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}"
|
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}"
|
||||||
@@ -588,6 +604,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _merge_pull_request(self, pull_number, commit_title, commit_message, merge_method):
|
def _merge_pull_request(self, pull_number, commit_title, commit_message, merge_method):
|
||||||
self.logger.info(f"Merging pull request: {pull_number}")
|
self.logger.info(f"Merging pull request: {pull_number}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/merge"
|
url = f"{self.base_url}/repos/{self.repo}/pulls/{pull_number}/merge"
|
||||||
@@ -606,6 +623,7 @@ class GitHubTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _delete_branch(self, branch_name):
|
def _delete_branch(self, branch_name):
|
||||||
self.logger.info(f"Deleting branch: {branch_name}")
|
self.logger.info(f"Deleting branch: {branch_name}")
|
||||||
url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}"
|
url = f"{self.base_url}/repos/{self.repo}/git/refs/heads/{branch_name}"
|
||||||
@@ -617,4 +635,4 @@ class GitHubTool(BaseTool):
|
|||||||
else:
|
else:
|
||||||
error_message = f"Error deleting branch: {response.status_code}\nResponse: {response.text}"
|
error_message = f"Error deleting branch: {response.status_code}\nResponse: {response.text}"
|
||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# tools/log_tool.py
|
# tools/log_tool.py
|
||||||
|
|
||||||
from .base_tool import BaseTool
|
from .base_tool import BaseTool
|
||||||
|
from .metrics import metrics
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@@ -49,6 +50,7 @@ class LogTool(BaseTool):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def execute(self, function_name, **kwargs):
|
def execute(self, function_name, **kwargs):
|
||||||
self.logger.info(f"Executing: {function_name}")
|
self.logger.info(f"Executing: {function_name}")
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ class LogTool(BaseTool):
|
|||||||
self.logger.error(error_message)
|
self.logger.error(error_message)
|
||||||
return error_message
|
return error_message
|
||||||
|
|
||||||
|
@metrics.measure
|
||||||
def _get_log_contents(self, line_count=150):
|
def _get_log_contents(self, line_count=150):
|
||||||
log_file_path = 'logs/output.log'
|
log_file_path = 'logs/output.log'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import cProfile
|
||||||
|
import pstats
|
||||||
|
import io
|
||||||
|
from functools import wraps
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
class Metrics:
|
||||||
|
def __init__(self):
|
||||||
|
self.call_count = defaultdict(int)
|
||||||
|
self.total_time = defaultdict(float)
|
||||||
|
|
||||||
|
def measure(self, func):
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
self.call_count[func.__name__] += 1
|
||||||
|
|
||||||
|
pr = cProfile.Profile()
|
||||||
|
pr.enable()
|
||||||
|
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
|
||||||
|
pr.disable()
|
||||||
|
s = io.StringIO()
|
||||||
|
ps = pstats.Stats(pr, stream=s).sort_stats('cumulative')
|
||||||
|
ps.print_stats()
|
||||||
|
|
||||||
|
# Extract the total time spent in the function
|
||||||
|
time_spent = float(s.getvalue().split('\n')[0].split()[-2])
|
||||||
|
self.total_time[func.__name__] += time_spent
|
||||||
|
|
||||||
|
return result
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def get_metrics(self):
|
||||||
|
metrics = {}
|
||||||
|
for func_name in self.call_count:
|
||||||
|
metrics[func_name] = {
|
||||||
|
'call_count': self.call_count[func_name],
|
||||||
|
'total_time': self.total_time[func_name],
|
||||||
|
'average_time': self.total_time[func_name] / self.call_count[func_name] if self.call_count[func_name] > 0 else 0
|
||||||
|
}
|
||||||
|
return metrics
|
||||||
|
|
||||||
|
# Create a global instance of Metrics
|
||||||
|
metrics = Metrics()
|
||||||
Reference in New Issue
Block a user