分享JMS流量统计面板
<i class="pstatus"> 本帖最后由 雪秋千 于 2025-3-14 18:05 编辑 </i><br /><br />
各位大侠有justmysocks的API的流量统计面板吗?自己用GPT写的太丑。<br />
下面是自己写的效果预览图<br />
<ignore_js_op>
<img src="https://hostloc.com/static/image/filetype/image.gif" border="0" class="vm" alt="" />
<span style="white-space: nowrap" id="attach_173187" onmouseover="showMenu({'ctrlid':this.id,'pos':'12'})">
<a href="https://hostloc.com/forum.php?mod=attachment&aid=MTczMTg3fGZlZWU3MWY1fDE3NDIwODA4NTl8MHwxMzk2MDI1" target="_blank">Screenshot 2025-03-14 180331.png</a>
<em class="xg1">(65.11 KB, 下载次数: 2)</em>
</span>
<div class="tip tip_4" id="attach_173187_menu" style="position: absolute; display: none" disautofocus="true">
<div class="tip_c xs0">
<div class="y"><span title="2025-3-14 18:03">前天18:03</span> 上传</div>
点击文件名下载附件
</div>
<div class="tip_horn"></div>
</div>
</ignore_js_op>
先把我的放上来吧<br />
1. 首先是本地存储数据的,定期30秒运行一次。因为jms更新时间差不多就是半分钟。<br /><div class="blockcode"><div id="code_W4X"><ol><li>import requests<br /><li>import json<br /><li>from datetime import datetime<br /><li><br /><li>API_URL = "https://justmysocks6.net/members/getbwcounter.php?service="<br /><li>HISTORY_FILE = "扶Q_usage_history.json"<br /><li><br /><li>def fetch_bw_counter():<br /><li>response = requests.get(API_URL)<br /><li>data = response.json()<br /><li># data = {"monthly_bw_limit_b": 1000000000000,<br /><li># "bw_counter_b": 651529129,<br /><li># "bw_reset_day_of_month": 13}<br /><li>return data["bw_counter_b"]<br /><li><br /><li>def load_history():<br /><li>try:<br /><li>with open(HISTORY_FILE, "r") as f:<br /><li> return json.load(f)<br /><li>except (IOError, ValueError):<br /><li>return []<br /><li><br /><li>def save_history(history):<br /><li>with open(HISTORY_FILE, "w") as f:<br /><li>json.dump(history, f, indent=2)<br /><li><br /><li>def record_usage():<br /><li># 1) Fetch the current usage<br /><li>current_bw = fetch_bw_counter()<br /><li>timestamp = datetime.utcnow().isoformat()<br /><li><br /><li># 2) Append new record to history<br /><li>history = load_history()<br /><li>history.append({<br /><li>"timestamp": timestamp,<br /><li>"bw_counter_b": current_bw<br /><li>})<br /><li>save_history(history)<br /><li><br /><li>if __name__ == "__main__":<br /><li>record_usage()<br /><li></ol></div><em onclick="copycode($('code_W4X'));">复制代码</em></div><br />
<br />
2. 第二是显示面板,第一个面板是总体使用量,第二个是在不同时间的速率,<br /><div class="blockcode"><div id="code_vEW"><ol><li>import json<br /><li>import pandas as pd<br /><li>from datetime import timedelta<br /><li>import dash<br /><li>from dash import dcc, html, Input, Output<br /><li>import plotly.graph_objs as go<br /><li><br /><li># ----- Utility Functions -----<br /><li><br /><li>def load_usage_data(file_path="扶Q_usage_history.json"):<br /><li>"""Load usage data from JSON, localize to America/Los_Angeles, then convert to UTC.<br /><li> Plotly will automatically render these timestamps in the visitor’s local time.<br /><li>"""<br /><li>with open(file_path, "r") as f:<br /><li>data = json.load(f)<br /><li>df = pd.DataFrame(data)<br /><li># Assume timestamps in the file are in California time.<br /><li>df['timestamp'] = pd.to_datetime(df['timestamp']).dt.tz_localize('America/Los_Angeles')<br /><li># Convert to UTC for consistent plotting.<br /><li>df['timestamp'] = df['timestamp'].dt.tz_convert('UTC')<br /><li>df.sort_values('timestamp', inplace=True)<br /><li>return df<br /><li><br /><li>def convert_bytes(value_bytes):<br /><li>"""<br /><li>Convert a byte value to a human-friendly string using a 1000 conversion factor.<br /><li>If the value in GB is less than 0.001, display in MB.<br /><li>If in MB is less than 0.001, display in B.<br /><li>"""<br /><li>value_gb = value_bytes / 1e9<br /><li>if value_gb >= 0.001:<br /><li>return f"{value_gb:.3f} GB"<br /><li>value_mb = value_bytes / 1e6<br /><li>if value_mb >= 0.001:<br /><li>return f"{value_mb:.3f} MB"<br /><li>return f"{value_bytes} B"<br /><li><br /><li>def aggregate_data(df, resolution, window):<br /><li>"""<br /><li>Aggregate usage data for a given resolution and time window.<br /><li>resolution: a pandas offset alias, e.g., 'T' for minute, 'H' for hour, 'D' for day, 'W' for week.<br /><li>window: timedelta object representing the lookback period.<br /><li>"""<br /><li>end_time = df['timestamp'].max()<br /><li>start_time = end_time - window<br /><li>df_window = df >= start_time].copy()<br /><li>if df_window.empty:<br /><li>return pd.DataFrame(columns=['timestamp', 'bw_counter_b'])<br /><li>df_window.set_index('timestamp', inplace=True)<br /><li>df_resampled = df_window.resample(resolution).last().dropna()<br /><li>df_resampled.reset_index(inplace=True)<br /><li>return df_resampled<br /><li><br /><li>def compute_usage_rates(df):<br /><li>"""<br /><li>Compute the incremental usage (difference between consecutive bw_counter_b) <br /><li>and time differences. Returns the DataFrame with a new column 'usage_diff'.<br /><li>"""<br /><li>df = df.copy()<br /><li>df['usage_diff'] = df['bw_counter_b'].diff()<br /><li>df['time_diff_sec'] = df['timestamp'].diff().dt.total_seconds()<br /><li>df['usage_rate'] = df['usage_diff'] / df['time_diff_sec']<br /><li>return df<br /><li><br /><li># ----- Dash App Setup -----<br /><li><br /><li>app = dash.Dash(__name__)<br /><li>server = app.server<br /><li><br /><li>app.layout = html.Div([<br /><li>html.H1("扶Q Data Usage Dashboard"),<br /><li>html.Div([<br /><li>html.Button("Minutes", id="btn-minutes", n_clicks=0),<br /><li>html.Button("Hourly", id="btn-hourly", n_clicks=0),<br /><li>html.Button("Daily", id="btn-daily", n_clicks=0),<br /><li>html.Button("Weekly", id="btn-weekly", n_clicks=0)<br /><li>], style={'marginBottom': '20px'}),<br /><li>html.Div(id="summary-stats", style={'marginBottom': '20px'}),<br /><li>dcc.Graph(id="usage-graph"),<br /><li>dcc.Graph(id="rate-graph"),<br /><li>dcc.Interval(id="interval-update", interval=60*1000, n_intervals=0)# update every minute<br /><li>])<br /><li><br /><li># ----- Callback to Update Graphs and Stats -----<br /><li><br /><li>@app.callback(<br /><li>,<br /><li><br /><li>)<br /><li>def update_dashboard(n_min, n_hour, n_day, n_week, n_interval):<br /><li>df = load_usage_data()<br /><li><br /><li># Determine which button was most recently pressed<br /><li>ctx = dash.callback_context<br /><li>if not ctx.triggered:<br /><li>resolution_choice = 'H'<br /><li>window = timedelta(hours=24)<br /><li>else:<br /><li>button_id = ctx.triggered['prop_id'].split('.')<br /><li>if button_id == "btn-minutes":<br /><li> resolution_choice = 'T'# minute resolution<br /><li> window = timedelta(hours=1)<br /><li>elif button_id == "btn-hourly":<br /><li> resolution_choice = 'H'<br /><li> window = timedelta(hours=24)<br /><li>elif button_id == "btn-daily":<br /><li> resolution_choice = 'D'<br /><li> window = timedelta(days=7)<br /><li>elif button_id == "btn-weekly":<br /><li> resolution_choice = 'W'<br /><li> window = timedelta(weeks=4)<br /><li>else:<br /><li> resolution_choice = 'H'<br /><li> window = timedelta(hours=24)<br /><li><br /><li>df_agg = aggregate_data(df, resolution_choice, window)<br /><li>df_rate = compute_usage_rates(df_agg)<br /><li><br /><li># ----- Cumulative Usage Figure -----<br /><li>cum_fig = go.Figure()<br /><li>cum_fig.add_trace(go.Scatter(<br /><li>x=df_agg['timestamp'],<br /><li>y=df_agg['bw_counter_b'] / 1e9,# cumulative usage in GB<br /><li>mode='lines+markers',<br /><li>name="Cumulative Usage (GB)",<br /><li>connectgaps=False<br /><li>))<br /><li>cum_fig.update_layout(<br /><li>title="扶Q Cumulative Usage Over Time",<br /><li>xaxis_title="Time",<br /><li>yaxis_title="Usage (GB)",<br /><li>hovermode="x unified"<br /><li>)<br /><li><br /><li># ----- Usage Rate Figure -----<br /><li>df_rate_clean = df_rate.dropna(subset=['usage_diff'])<br /><li>if not df_rate_clean.empty:<br /><li>max_diff = df_rate_clean['usage_diff'].max()<br /><li>if max_diff / 1e9 >= 0.001:<br /><li> factor = 1e9<br /><li> y_label = "Usage per Interval (GB)"<br /><li>elif max_diff / 1e6 >= 0.001:<br /><li> factor = 1e6<br /><li> y_label = "Usage per Interval (MB)"<br /><li>else:<br /><li> factor = 1<br /><li> y_label = "Usage per Interval (B)"<br /><li>usage_diff_converted = df_rate_clean['usage_diff'] / factor<br /><li>else:<br /><li>usage_diff_converted = []<br /><li>y_label = "Usage per Interval"<br /><li><br /><li>rate_fig = go.Figure()<br /><li>rate_fig.add_trace(go.Scatter(<br /><li>x=df_rate_clean['timestamp'],<br /><li>y=usage_diff_converted,<br /><li>mode='lines+markers',<br /><li>name="Interval Usage",<br /><li>connectgaps=False<br /><li>))<br /><li>rate_fig.update_layout(<br /><li>title="扶Q Usage Rate Over Time",<br /><li>xaxis_title="Time",<br /><li>yaxis_title=y_label,<br /><li>hovermode="x unified"<br /><li>)<br /><li><br /><li># ----- Summary Statistics -----<br /><li>if not df_rate['usage_rate'].dropna().empty:<br /><li>avg_rate = df_rate['usage_rate'].dropna().mean()# bytes per second<br /><li>avg_per_min = convert_bytes(avg_rate * 60)<br /><li>avg_per_hour = convert_bytes(avg_rate * 3600)<br /><li>avg_per_day = convert_bytes(avg_rate * 3600 * 24)<br /><li>avg_per_week = convert_bytes(avg_rate * 3600 * 24 * 7)<br /><li>else:<br /><li>avg_per_min = avg_per_hour = avg_per_day = avg_per_week = "N/A"<br /><li><br /><li>summary = html.Div([<br /><li>html.P(f"Average Usage per Minute: {avg_per_min}"),<br /><li>html.P(f"Average Usage per Hour: {avg_per_hour}"),<br /><li>html.P(f"Average Usage per Day: {avg_per_day}"),<br /><li>html.P(f"Average Usage per Week: {avg_per_week}")<br /><li>])<br /><li><br /><li>return cum_fig, rate_fig, summary<br /><li><br /><li>if __name__ == '__main__':<br /><li>app.run_server(debug=True)<br /><li></ol></div><em onclick="copycode($('code_vEW'));">复制代码</em></div>
页:
[1]