Serveral improvements, including sorting of output tags, ignore error if any tag fails, add apex mail queue, smtp settings, top redo generating sql and apex bots usage

This commit is contained in:
Zulqarnain 2024-11-20 03:20:49 -05:00
parent f54a39aee8
commit fe39829fa2
7 changed files with 395 additions and 44 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode/
playground/
venv/
venv/
src/custom.json

View File

@ -38,9 +38,9 @@ def read_log(log_file, lines):
@app.route('/get_logs', methods=['GET'])
def get_logs():
tags = request.args.getlist("tags")
tags = request.args.getlist("tags") # Get tags in the order they appear in the query
try:
# Load main config-tags.json
# Load main config.json
with open('/opt/ticket-ai/src/config.json') as config_file:
config = json.load(config_file)
@ -49,40 +49,51 @@ def get_logs():
if os.path.exists(custom_config_path):
with open(custom_config_path) as custom_file:
custom_config = json.load(custom_file)
for key, value in custom_config.items():
if key in config:
config[key].extend(value)
else:
config[key] = value
for custom_tag in custom_config["tags"]:
# Remove matching tags in config if custom.json supersedes
config["tags"] = [tag for tag in config["tags"] if tag["tag"] != custom_tag["tag"]]
config["tags"].append(custom_tag)
response = {}
# Process each tag in the list
response_list = [] # Use a list to store the responses in order
tags_found = False
# Process each tag in the given order
for tag in tags:
# Search for the tag in commands and logs
tag_data = next((item for item in config["tags"] if item["tag"] == tag), None)
if not tag_data:
response[tag] = "Tag not found"
continue
# Determine if the tag is a command or a log
if tag_data["type"] == "command":
response[tag] = f"```\n{os.popen(tag_data['content']).read()}\n```"
elif tag_data["type"] == "log":
log_file = tag_data["content"]
# Replace any placeholders in the log file path
log_file = replace_placeholders(log_file)
if "*" in log_file:
# Handle wildcard in log file path
response[tag] = f"```\n{read_log_from_dir(*split_directory_and_file(log_file), tag_data['lines'])}\n```"
else:
# Regular log file
response[tag] = f"```\n{read_log(log_file, tag_data['lines'])}\n```"
try:
# Search for the tag in commands and logs
tag_data = next((item for item in config["tags"] if item["tag"] == tag), None)
if not tag_data:
response_list.append({tag: "Tag not found"})
continue
tags_found = True # At least one valid tag is found
# Determine if the tag is a command or a log
if tag_data["type"] == "command":
response_list.append({tag: f"```\n{os.popen(tag_data['content']).read()}\n```"})
elif tag_data["type"] == "log":
log_file = tag_data["content"]
# Replace any placeholders in the log file path
log_file = replace_placeholders(log_file)
if "*" in log_file:
# Handle wildcard in log file path
response_list.append({tag: f"```\n{read_log_from_dir(*split_directory_and_file(log_file), tag_data['lines'])}\n```"})
else:
# Regular log file
response_list.append({tag: f"```\n{read_log(log_file, tag_data['lines'])}\n```"})
except Exception as e:
# Log the error and proceed
response_list.append({tag: f"Error: {str(e)}"})
# If no tags were found, return HTTP 400 with an error message
if not tags_found:
return jsonify({"error": "None of the requested tags were found."}), 400
except Exception as e:
return jsonify({"error": str(e)})
return jsonify(response)
return jsonify({"error": str(e)}), 500
# Return the response as a list to guarantee order
return jsonify(response_list)
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0")

View File

@ -25,6 +25,26 @@
"type": "command",
"content": "/opt/ticket-ai/src/scripts/apexUsage.sh;sleep 5;cat /tmp/apex_usage.tmp"
},
{
"tag": "apex_mail_queue",
"type": "command",
"content": "/opt/ticket-ai/src/scripts/apex_mail_queue.sh;sleep 5;cat /tmp/apex_mail_queue.tmp"
},
{
"tag": "apex_smtp_settings",
"type": "command",
"content": "/opt/ticket-ai/src/scripts/apex_smtp_settings.sh;sleep 5;cat /tmp/apex_smtp_settings.tmp"
},
{
"tag": "apex_bot_hits",
"type": "command",
"content": "/opt/ticket-ai/src/scripts/apexBots.sh;sleep 5;cat /tmp/apex_bots.tmp"
},
{
"tag": "top_redo_sql",
"type": "command",
"content": "/opt/ticket-ai/src/scripts/topRedoSQL.sh;sleep 5;cat /tmp/top_redo_sql.tmp"
},
{
"tag": "top",
"type": "command",
@ -36,27 +56,22 @@
"content": "iostat -x 1 3"
},
{
"tag": "df",
"type": "command",
"content": "df -h | head -n 1 && df -h | grep '^/dev/sd'"
},
{
"tag": "processfinder",
"tag": "process_finder",
"type": "command",
"content": "/opt/ticket-ai/src/scripts/processfinder.sh;sleep 5;cat /tmp/findsql.tmp"
},
{
"tag": "ordsconfig",
"tag": "ords_config",
"type": "command",
"content": "cat /opt/ords/config/databases/default/pool.xml"
},
{
"tag": "datetime",
"tag": "date_time",
"type": "command",
"content": "echo Current Date and time on server: ; date"
},
{
"tag": "apacheerrorlogs",
"tag": "apache_error_logs",
"type": "command",
"content": "find {virtualmin_error_log} -type f -name '*error_log*' -mmin -15 -exec sh -c 'echo \"===== {} =====\"; tail -n 50 {}' \\;"
},
@ -135,7 +150,7 @@
"lines": 150
},
{
"tag": "os-release",
"tag": "os_release",
"type": "log",
"content": "/etc/os-release",
"lines": 150
@ -155,7 +170,7 @@
{
"tag": "var_log_mariadb",
"type": "log",
"content": "/var/log/mariadb/mariadb.log",
"content": "/var/log/mariadb/mariadb.log1",
"lines": 150
}
]

87
src/scripts/apexBots.sh Executable file
View File

@ -0,0 +1,87 @@
#!/bin/bash
# File paths for output
OUTPUT_FILE="/tmp/apex_bots.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to execute the Bot Hits query in a specific container
run_query() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo on
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT Bot Hits on APEX for container: $container_name;
SELECT
AGENT,
COUNT(*) AS HIT_COUNT
FROM
APEX_WORKSPACE_ACTIVITY_LOG
WHERE
VIEW_DATE BETWEEN SYSDATE - (1/24) AND SYSDATE
AND (
UPPER(AGENT) LIKE '%BOT%' OR
UPPER(AGENT) LIKE '%YANDEX%' OR
UPPER(AGENT) LIKE '%MJ12BOT%' OR
UPPER(AGENT) LIKE '%INDEX%' OR
UPPER(AGENT) LIKE '%.RU%' OR
UPPER(AGENT) LIKE '%GOOGLE%' OR
UPPER(AGENT) LIKE '%FACEBOOK%'
)
GROUP BY
AGENT
ORDER BY
HIT_COUNT DESC;
exit;
EOF
"
}
# Run the query for the CDB (root container)
# echo "Gathering Bot Hits for CDB (root container)..." >> "$OUTPUT_FILE"
# run_query 'CDB\$ROOT'
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<'EOF'
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\$pdbs WHERE NAME NOT IN ('PDB\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering Bot Hits for PDB: $PDB..." >> "$OUTPUT_FILE"
run_query "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f "$PDB_LIST_FILE"

74
src/scripts/apex_mail_queue.sh Executable file
View File

@ -0,0 +1,74 @@
#!/bin/bash
# File paths for output
OUTPUT_FILE="/tmp/apex_mail_queue.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to execute the APEX Mail Queue query in a specific container
run_query() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo on
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT APEX Mail Queue for container: $container_name;
SELECT
WORKSPACE_NAME,
COUNT(*) AS TOTAL_EMAILS,
SUM(CASE WHEN MAIL_SEND_COUNT = 0 THEN 1 ELSE 0 END) AS UNSENT_EMAILS,
SUM(CASE WHEN MAIL_SEND_ERROR IS NOT NULL THEN 1 ELSE 0 END) AS EMAILS_WITH_ERRORS
FROM
APEX_MAIL_QUEUE
GROUP BY
WORKSPACE_NAME
ORDER BY
WORKSPACE_NAME;
exit;
EOF
"
}
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\\\$pdbs WHERE NAME NOT IN ('PDB\\\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering APEX Mail Queue for PDB: $PDB..." >> "$OUTPUT_FILE"
run_query "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f "$PDB_LIST_FILE"

View File

@ -0,0 +1,81 @@
#!/bin/bash
# File paths for output
OUTPUT_FILE="/tmp/apex_smtp_settings.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to execute the SMTP Settings query in a specific container
run_query() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo on
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT APEX SMTP Settings for container: $container_name;
SELECT
'SMTP_HOST_ADDRESS' AS PARAMETER_NAME, APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_HOST_ADDRESS') AS PARAMETER_VALUE
FROM
DUAL
UNION ALL
SELECT
'SMTP_PORT', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_PORT')
FROM
DUAL
UNION ALL
SELECT
'SMTP_USERNAME', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_USERNAME')
FROM
DUAL
UNION ALL
SELECT
'SMTP_AUTH_REQUIRED', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_AUTH_REQUIRED')
FROM
DUAL;
exit;
EOF
"
}
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\\\$pdbs WHERE NAME NOT IN ('PDB\\\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering APEX SMTP Settings for PDB: $PDB..." >> "$OUTPUT_FILE"
run_query "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f "$PDB_LIST_FILE"

82
src/scripts/topRedoSQL.sh Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
# File paths for output
OUTPUT_FILE="/tmp/top_redo_sql.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to execute the Redo Size query in a specific container
run_query() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo on
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT Top redo size sessions for container: $container_name;
SELECT
S.SID,
S.SERIAL#,
Q.SQL_TEXT,
S.USERNAME,
ROUND(R.VALUE / (1024 * 1024), 2) AS REDO_SIZE_MB
FROM
V\\\$SESSION S
JOIN
V\\\$SQL Q ON S.SQL_ADDRESS = Q.ADDRESS
JOIN
V\\\$SESSTAT R ON S.SID = R.SID
JOIN
V\\\$STATNAME N ON R.STATISTIC# = N.STATISTIC#
WHERE
N.NAME = 'redo size'
AND S.LAST_CALL_ET < 7200 -- Filter sessions active within last 2 hours
ORDER BY
R.VALUE DESC
FETCH FIRST 10 ROWS ONLY;
exit;
EOF
"
}
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\\\$pdbs WHERE NAME NOT IN ('PDB\\\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering top redo size sessions for PDB: $PDB..." >> "$OUTPUT_FILE"
run_query "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f