PR Type
Enhancement
Description
-
Add automated network speed report generation script
-
Implement email functionality with chart and Excel attachments
-
Parse speedtest log data with regex pattern matching
-
Generate visualization and statistical analysis of network performance
Diagram Walkthrough
flowchart LR
A["Log File"] --> B["Parse Data"]
B --> C["Generate Chart"]
B --> D["Create Excel"]
C --> E["Email Report"]
D --> E
E --> F["Send Notification"]
File Walkthrough
| Relevant files |
|---|
| Enhancement |
Khai_send_report.pyNetwork speed reporting automation script
Khai_send_report.py
- Implements log file parsing with regex for speedtest results
- Creates matplotlib charts and Excel reports from network data
- Configures SMTP email sending with file attachments
- Adds statistical analysis and automated report generation
|
+100/-0 |
|
PR Reviewer Guide 🔍
Here are some key observations to aid the review process:
| ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪ |
| 🧪 No relevant tests |
🔒 Security concerns
Sensitive information exposure: Hardcoded Gmail sender, receiver, and app password are committed in code. This exposes credentials and risks account compromise. Move these to environment variables (e.g., EMAIL_SENDER, EMAIL_PASSWORD, EMAIL_RECEIVER) and load via os.environ; ensure credentials are rotated and removed from history. Additionally, validate and sanitize attachments' paths to avoid unintended file disclosures if paths become user-controlled in the future. |
⚡ Recommended focus areas for review
Hardcoded Secrets
The SMTP app password and email addresses are hardcoded in the script. These should be moved to environment variables or a secrets manager and excluded from source control.
EMAIL_SENDER = "[email protected]"
EMAIL_PASSWORD = "zoelpdyuokwrknnp" # App password, không dùng password Gmail trực tiếp
EMAIL_RECEIVER = "[email protected]"
REPORT_PERIOD_DAYS = 1 # 1 = hàng ngày, 7 = hàng tuần
Error Handling
File I/O, SMTP login/send, and plotting lack try/except handling; failures (missing log file, bad attachments, SMTP errors) will crash the script without actionable logs.
with open(LOG_FILE, "r") as f:
for line in f:
match = pattern.match(line.strip())
if match:
records.append(match.groupdict())
df = pd.DataFrame(records)
df["time"] = pd.to_datetime(df["time"])
df["dl"] = df["dl"].astype(float)
df["ul"] = df["ul"].astype(float)
df["ping"] = df["ping"].astype(float)
# Lọc theo khoảng thời gian
start_date = datetime.now() - timedelta(days=REPORT_PERIOD_DAYS)
df = df[df["time"] >= start_date]
if df.empty:
print("Không có dữ liệu trong khoảng thời gian.")
exit()
# Vẽ biểu đồ
plt.figure(figsize=(10, 6))
plt.plot(df["time"], df["dl"], label="Download (Mbps)", marker="o")
plt.plot(df["time"], df["ul"], label="Upload (Mbps)", marker="o")
plt.xlabel("Thời gian")
plt.ylabel("Tốc độ (Mbps)")
plt.title("Báo cáo tốc độ mạng")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig("report_chart.png")
# Lưu Excel
excel_path = "report_data.xlsx"
df.to_excel(excel_path, index=False)
# Nội dung email
subject = f"Báo cáo tốc độ mạng {REPORT_PERIOD_DAYS} ngày gần nhất"
body = f"""
Xin chào,
Đây là báo cáo tốc độ mạng {REPORT_PERIOD_DAYS} ngày gần nhất.
📊 Thống kê:
- Số lần đo: {len(df)}
- Download trung bình: {df['dl'].mean():.2f} Mbps
- Upload trung bình: {df['ul'].mean():.2f} Mbps
- Ping trung bình: {df['ping'].mean():.2f} ms
File đính kèm:
- report_chart.png (biểu đồ)
- report_data.xlsx (dữ liệu chi tiết)
Trân trọng,
Hệ thống LibreSpeed
"""
# Gửi email
msg = MIMEMultipart()
msg["From"] = EMAIL_SENDER
msg["To"] = EMAIL_RECEIVER
msg["Subject"] = subject
msg.attach(MIMEText(body, "plain"))
# Đính kèm file
for file_path in ["report_chart.png", excel_path]:
with open(file_path, "rb") as f:
part = MIMEApplication(f.read(), Name=file_path)
part["Content-Disposition"] = f'attachment; filename="{file_path}"'
msg.attach(part)
# Gửi qua Gmail SMTP
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
server.login(EMAIL_SENDER, EMAIL_PASSWORD)
server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, msg.as_string())
Regex Robustness
The strict regex may fail on minor format variations; consider using re.search and validating parsed fields, with logging for skipped lines.
pattern = re.compile(
r"(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \| IP: (?P<ip>[\d\.]+) \| Download: (?P<dl>[\d\.]+) Mbps \| Upload: (?P<ul>[\d\.]+) Mbps \| Ping: (?P<ping>[\d\.]+) ms"
)
records = []
with open(LOG_FILE, "r") as f:
for line in f:
match = pattern.match(line.strip())
if match:
records.append(match.groupdict())
|
PR Code Suggestions ✨
Explore these optional code suggestions:
| Category | Suggestion | Impact |
| Security |
Remove hardcoded email credentials
Do not hardcode credentials in source code; this is a critical security risk and can leak secrets. Read the sender, receiver, and app password from environment variables (with sane fallbacks or fail fast) and document required env vars. This also prevents accidental credential exposure in version control.
Khai_send_report.py [12-14]
-EMAIL_SENDER = "[email protected]"
-EMAIL_PASSWORD = "zoelpdyuokwrknnp" # App password, không dùng password Gmail trực tiếp
-EMAIL_RECEIVER = "[email protected]"
+import os
+EMAIL_SENDER = os.getenv("EMAIL_SENDER")
+EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD") # Use Gmail App Password
+EMAIL_RECEIVER = os.getenv("EMAIL_RECEIVER", EMAIL_SENDER)
+
+if not EMAIL_SENDER or not EMAIL_PASSWORD:
+ raise RuntimeError("Missing EMAIL_SENDER or EMAIL_PASSWORD environment variables.")
+
- [ ] Apply / Chat <!-- /improve --apply_suggestion=0 -->
Suggestion importance[1-10]: 10
__
Why: The suggestion addresses a critical security vulnerability by removing hardcoded credentials from the source code, which is a best practice to prevent secret leaks.
| High
|
| Possible issue |
Add robust log read error handling
If the log file is missing or unreadable, or regex yields no matches, the script will crash or create empty DataFrames with confusing errors. Add error handling for file I/O and the empty-records case, and use a non-zero exit code via sys.exit(1) to signal failure in automation.
Khai_send_report.py [24-42]
-with open(LOG_FILE, "r") as f:
- for line in f:
- match = pattern.match(line.strip())
- if match:
- records.append(match.groupdict())
+import sys
+try:
+ with open(LOG_FILE, "r") as f:
+ for line in f:
+ match = pattern.match(line.strip())
+ if match:
+ records.append(match.groupdict())
+except FileNotFoundError:
+ print(f"Log file not found: {LOG_FILE}")
+ sys.exit(1)
+except OSError as e:
+ print(f"Error reading log file '{LOG_FILE}': {e}")
+ sys.exit(1)
+
+if not records:
+ print("No valid log records found.")
+ sys.exit(1)
df = pd.DataFrame(records)
df["time"] = pd.to_datetime(df["time"])
df["dl"] = df["dl"].astype(float)
df["ul"] = df["ul"].astype(float)
df["ping"] = df["ping"].astype(float)
-# Lọc theo khoảng thời gian
start_date = datetime.now() - timedelta(days=REPORT_PERIOD_DAYS)
df = df[df["time"] >= start_date]
if df.empty:
print("Không có dữ liệu trong khoảng thời gian.")
- exit()
+ sys.exit(1)
- [ ] Apply / Chat <!-- /improve --apply_suggestion=1 -->
Suggestion importance[1-10]: 8
__
Why: The suggestion improves the script's robustness by adding essential error handling for file I/O operations, preventing crashes from a missing log file and providing clearer failure diagnostics.
| Medium
|
Handle attachment and SMTP failures
If attachments are missing or SMTP fails, the script will crash without clear diagnostics. Add try/except around attachment reading and SMTP sending, and fail with explicit messages to aid automation and retries.
Khai_send_report.py [88-98]
-# Đính kèm file
+import sys
+# Đính kèm file với xử lý lỗi
for file_path in ["report_chart.png", excel_path]:
- with open(file_path, "rb") as f:
- part = MIMEApplication(f.read(), Name=file_path)
- part["Content-Disposition"] = f'attachment; filename="{file_path}"'
- msg.attach(part)
+ try:
+ with open(file_path, "rb") as f:
+ part = MIMEApplication(f.read(), Name=file_path)
+ part["Content-Disposition"] = f'attachment; filename="{file_path}"'
+ msg.attach(part)
+ except OSError as e:
+ print(f"Attachment error for '{file_path}': {e}")
+ sys.exit(1)
-# Gửi qua Gmail SMTP
-with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
- server.login(EMAIL_SENDER, EMAIL_PASSWORD)
- server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, msg.as_string())
+# Gửi qua Gmail SMTP với xử lý lỗi
+try:
+ with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
+ server.login(EMAIL_SENDER, EMAIL_PASSWORD)
+ server.sendmail(EMAIL_SENDER, EMAIL_RECEIVER, msg.as_string())
+except smtplib.SMTPException as e:
+ print(f"SMTP error: {e}")
+ sys.exit(1)
- [ ] Apply / Chat <!-- /improve --apply_suggestion=2 -->
Suggestion importance[1-10]: 8
__
Why: This suggestion correctly identifies and fixes potential runtime errors by adding try...except blocks for file attachment and SMTP operations, making the script more reliable against I/O or network issues.
| Medium
|
- [ ] More <!-- /improve --more_suggestions=true -->
| |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This pull request was automatically closed due to inactivity.