Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: db performance schema report generator api #129

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions agent/database.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from decimal import Decimal
from __future__ import annotations

Check failure on line 2 in agent/database.py

View workflow job for this annotation

GitHub Actions / Ruff

Ruff (F404)

agent/database.py:2:1: F404 `from __future__` imports must occur at the beginning of the file

import json
import os
Expand Down Expand Up @@ -275,3 +276,70 @@
}
)
return sorted(stalks, key=lambda x: x["name"])

@job("Fetch Performance Report")
def get_performance_report(self, private_ip, mariadb_root_password, reports=[]):

Check failure on line 281 in agent/database.py

View workflow job for this annotation

GitHub Actions / Ruff

Ruff (C901)

agent/database.py:281:9: C901 `get_performance_report` is too complex (13 > 8)

Check failure on line 281 in agent/database.py

View workflow job for this annotation

GitHub Actions / Ruff

Ruff (B006)

agent/database.py:281:81: B006 Do not use mutable data structures for argument defaults
# `reports` is a list of reports to fetch. If empty, fetch all reports.
mariadb = MySQLDatabase(
"mysql",
user="root",
password=mariadb_root_password,
host=private_ip,
port=3306,
)

reports_sql = {
"total_allocated_memory": "select total_allocated from sys.`x$memory_global_total`",
"top_memory_by_event": "select * from sys.`x$memory_global_by_current_bytes`",
"top_memory_by_user": "select * from sys.`x$memory_by_user_by_current_bytes`",
"top_memory_by_host": "select * from sys.`x$memory_by_host_by_current_bytes`",
"top_memory_by_thread": "select * from sys.`x$memory_by_thread_by_current_bytes`",
"top_io_by_file_activity_report": "select * from sys.`x$io_global_by_file_by_bytes`",
"top_io_by_file_by_time": "select * from sys.`x$io_global_by_file_by_latency`",
"top_io_by_event_category": "select * from sys.`x$io_global_by_wait_by_bytes`",
"top_io_in_time_by_event_category": "select * from sys.`x$io_global_by_wait_by_latency`",
"top_io_by_user_or_thread": "select * from sys.`x$io_by_thread_by_latency`",
"statement_analysis": "select * from sys.`x$statement_analysis`",
"statements_in_highest_5_percentile": "select * from sys.`x$statements_with_runtimes_in_95th_percentile`",

Check failure on line 303 in agent/database.py

View workflow job for this annotation

GitHub Actions / Ruff

Ruff (E501)

agent/database.py:303:111: E501 Line too long (118 > 110)
"statements_using_temp_tables": "select * from sys.`statements_with_temp_tables`",
"statements_with_sorting": "select * from sys.`statements_with_sorting`",
"statements_with_full_table_scans": "select * from sys.`statements_with_full_table_scans`",
"statements_with_errors_or_warnings": "select * from sys.`statements_with_errors_or_warnings`",
"schema_index_statistics": "select * from sys.`x$schema_index_statistics`",
"schema_table_statistics": "select * from sys.`x$schema_table_statistics`",
"schema_table_statistics_with_innodb_buffer": "select * from sys.`x$schema_table_statistics_with_buffer`",

Check failure on line 310 in agent/database.py

View workflow job for this annotation

GitHub Actions / Ruff

Ruff (E501)

agent/database.py:310:111: E501 Line too long (118 > 110)
"schema_tables_with_full_table_scans": "select * from sys.`schema_tables_with_full_table_scans`",
"schema_unused_indexes": "select * from sys.`schema_unused_indexes`",
"global_waits_by_time": "select * from sys.`x$waits_global_by_latency`",
"waits_by_user_by_time": "select * from sys.`x$waits_by_user_by_latency`",
"wait_classes_by_time": "select * from sys.`x$wait_classes_global_by_latency`",
"waits_classes_by_avg_time": "select * from sys.`x$wait_classes_global_by_avg_latency`",
"innodb_buffer_stats_by_schema": "select * from sys.`x$innodb_buffer_stats_by_schema`",
"innodb_buffer_stats_by_table": "select * from sys.`x$innodb_buffer_stats_by_table`",
"user_resource_use_overview": "select * from sys.`x$user_summary`",
"user_resource_use_io_statistics": "select * from sys.`x$user_summary_by_file_io_type`",
"user_resource_use_statement_statistics": "select * from sys.`x$user_summary_by_statement_type`",
}

data = {}
for key, sql in reports_sql.items():
if key in reports:
data[key] = self.sql(mariadb, sql)
if key == "total_allocated_memory":
data[key] = data[key][0]["total_allocated"]

# convert Decimal to float
for key, value in data.items():
if isinstance(value, list):
for row in value:
for column in row:
if isinstance(row[column], Decimal):
row[column] = float(row[column])
elif isinstance(value, dict):
for column in value:
if isinstance(value[column], Decimal):
value[column] = float(value[column])
elif isinstance(value, Decimal):
data[key] = float(value)

return data
7 changes: 7 additions & 0 deletions agent/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,13 @@ def get_stalk(stalk):
return jsonify(DatabaseServer().get_stalk(stalk))


@application.route("/database/performance_report", methods=["POST"])
def get_performance_report():
data = request.json
job = DatabaseServer().get_performance_report(**data)
return {"job": job}


@application.route("/database/deadlocks", methods=["POST"])
def get_database_deadlocks():
data = request.json
Expand Down
Loading