mirror of
https://github.com/optim-enterprises-bv/nDPId-2.git
synced 2025-11-05 12:47:53 +00:00
* TCP timeout after FIN/RST: switched back to the value from a35fc1d5ea
* py-flow-info: reset 'guessed' flag after detection/detection-update received
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
277 lines
9.2 KiB
Python
277 lines
9.2 KiB
Python
import math
|
|
|
|
import dash
|
|
from dash.dependencies import Input, Output, State
|
|
import dash_core_components as dcc
|
|
import dash_html_components as html
|
|
import dash_daq as daq
|
|
import dash_table as dt
|
|
|
|
import plotly.graph_objects as go
|
|
|
|
global shared_flow_dict
|
|
|
|
app = dash.Dash(__name__)
|
|
|
|
def generate_box():
|
|
return { \
|
|
'display': 'flex', 'flex-direction': 'row', \
|
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)', \
|
|
'background-color': '#082255' \
|
|
}
|
|
|
|
def generate_led_display(div_id, label_name):
|
|
return daq.LEDDisplay( \
|
|
id=div_id, \
|
|
label={'label': label_name, 'style': {'color': '#C4CDD5'}}, \
|
|
labelPosition='bottom', \
|
|
value='0', \
|
|
backgroundColor='#082255', \
|
|
color='#C4CDD5', \
|
|
)
|
|
|
|
def generate_gauge(div_id, label_name, max_value=10):
|
|
return daq.Gauge( \
|
|
id=div_id, \
|
|
value=0, \
|
|
label={'label': label_name, 'style': {'color': '#C4CDD5'}}, \
|
|
max=max_value, \
|
|
min=0, \
|
|
)
|
|
|
|
app.layout = html.Div([
|
|
html.Div(children=[
|
|
dcc.Interval(id="default-interval", interval=1 * 2000, n_intervals=0),
|
|
|
|
html.Div(children=[
|
|
|
|
dt.DataTable(
|
|
id='table-info',
|
|
columns=[{'id': c.lower(), 'name': c, 'editable': False}
|
|
for c in ['Key', 'Value']],
|
|
)
|
|
|
|
], style={'display': 'flex', 'flex-direction': 'row'}),
|
|
|
|
html.Div(children=[
|
|
dcc.Graph(
|
|
id='piechart-flows',
|
|
config={
|
|
'displayModeBar': False,
|
|
},
|
|
),
|
|
], style={'padding': 10, 'flex': 1}),
|
|
|
|
html.Div(children=[
|
|
dcc.Graph(
|
|
id='piechart-midstream-flows',
|
|
config={
|
|
'displayModeBar': False,
|
|
},
|
|
),
|
|
], style={'padding': 10, 'flex': 1}),
|
|
|
|
html.Div(children=[
|
|
dcc.Graph(
|
|
id='piechart-risky-flows',
|
|
config={
|
|
'displayModeBar': False,
|
|
},
|
|
),
|
|
], style={'padding': 10, 'flex': 1}),
|
|
], style=generate_box()),
|
|
|
|
html.Div(children=[
|
|
dcc.Interval(id="graph-interval", interval=4 * 1000, n_intervals=0),
|
|
dcc.Store(id="graph-traces"),
|
|
|
|
html.Div(children=[
|
|
dcc.Graph(
|
|
id="graph-flows",
|
|
config={
|
|
'displayModeBar': False,
|
|
},
|
|
style={'height':'60vh'},
|
|
),
|
|
], style={'padding': 10, 'flex': 1})
|
|
], style=generate_box()),
|
|
])
|
|
|
|
def build_gauge(key, max_value=100):
|
|
gauge_max = int(max(max_value,
|
|
shared_flow_dict[key]))
|
|
grad_green = [0, int(gauge_max * 1/3)]
|
|
grad_yellow = [int(gauge_max * 1/3), int(gauge_max * 2/3)]
|
|
grad_red = [int(gauge_max * 2/3), gauge_max]
|
|
|
|
grad_dict = \
|
|
{ \
|
|
"gradient":True, \
|
|
"ranges":{ \
|
|
"green":grad_green, \
|
|
"yellow":grad_yellow, \
|
|
"red":grad_red \
|
|
} \
|
|
}
|
|
|
|
return shared_flow_dict[key], gauge_max, grad_dict
|
|
|
|
def build_piechart(labels, values):
|
|
lay = dict(
|
|
plot_bgcolor = '#082255',
|
|
paper_bgcolor = '#082255',
|
|
font={"color": "#fff"},
|
|
autosize=True,
|
|
height=250,
|
|
margin = {'autoexpand': False, 'b': 0, 'l': 0, 'r': 0, 't': 0, 'pad': 0},
|
|
width = 500,
|
|
uniformtext_minsize = 12,
|
|
uniformtext_mode = 'hide',
|
|
)
|
|
|
|
return go.Figure(layout=lay, data=[go.Pie(labels=labels, values=values, textinfo='percent', textposition='inside')])
|
|
|
|
def prettifyBytes(bytes_received):
|
|
size_names = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
if bytes_received == 0:
|
|
i = 0
|
|
else:
|
|
i = min(int(math.floor(math.log(bytes_received, 1024))), len(size_names) - 1)
|
|
p = math.pow(1024, i)
|
|
s = round(bytes_received / p, 2)
|
|
return '{:.2f} {}'.format(s, size_names[i])
|
|
|
|
@app.callback(output=[Output('table-info', 'data'),
|
|
Output('piechart-flows', 'figure'),
|
|
Output('piechart-midstream-flows', 'figure'),
|
|
Output('piechart-risky-flows', 'figure')],
|
|
|
|
inputs=[Input('default-interval', 'n_intervals')])
|
|
def update_led_gauge(n):
|
|
return [[{'key': 'Total JSON Events', 'value': shared_flow_dict['total-events']},
|
|
{'key': 'Total JSON Bytes', 'value': prettifyBytes(shared_flow_dict['total-bytes'])},
|
|
{'key': 'Total Flows', 'value': shared_flow_dict['total-flows']},
|
|
{'key': 'Total Risky Flows', 'value': shared_flow_dict['total-risky-flows']},
|
|
{'key': 'Total Midstream Flows', 'value': shared_flow_dict['total-midstream-flows']},
|
|
{'key': 'Total Guessed Flows', 'value': shared_flow_dict['total-guessed-flows']},
|
|
{'key': 'Total Not Detected Flows', 'value': shared_flow_dict['total-not-detected-flows']}],
|
|
build_piechart(['Detected', 'Guessed', 'Undetected', 'Unclassified'],
|
|
[shared_flow_dict['current-detected-flows'],
|
|
shared_flow_dict['current-guessed-flows'],
|
|
shared_flow_dict['current-not-detected-flows'],
|
|
shared_flow_dict['current-flows']
|
|
- shared_flow_dict['current-detected-flows']
|
|
- shared_flow_dict['current-guessed-flows']
|
|
- shared_flow_dict['current-not-detected-flows']]),
|
|
build_piechart(['Midstream', 'Not Midstream'],
|
|
[shared_flow_dict['current-midstream-flows'],
|
|
shared_flow_dict['current-flows'] -
|
|
shared_flow_dict['current-midstream-flows']]),
|
|
build_piechart(['Risky', 'Not Risky'],
|
|
[shared_flow_dict['current-risky-flows'],
|
|
shared_flow_dict['current-flows'] -
|
|
shared_flow_dict['current-risky-flows']])]
|
|
|
|
@app.callback(output=[Output('graph-flows', 'figure'),
|
|
Output('graph-traces', 'data')],
|
|
inputs=[Input('graph-interval', 'n_intervals'),
|
|
Input('graph-interval', 'interval')],
|
|
state=[State('graph-traces', 'data')])
|
|
def update_graph(n, i, traces):
|
|
if traces is None:
|
|
traces = ([], [], [], [], [], [])
|
|
|
|
max_bins = 50
|
|
|
|
traces[0].append(shared_flow_dict['current-flows'])
|
|
traces[1].append(shared_flow_dict['current-risky-flows'])
|
|
traces[2].append(shared_flow_dict['current-midstream-flows'])
|
|
traces[3].append(shared_flow_dict['current-guessed-flows'])
|
|
traces[4].append(shared_flow_dict['current-not-detected-flows'])
|
|
traces[5].append(shared_flow_dict['current-flows']
|
|
- shared_flow_dict['current-detected-flows']
|
|
- shared_flow_dict['current-guessed-flows']
|
|
- shared_flow_dict['current-not-detected-flows'])
|
|
if len(traces[0]) > max_bins:
|
|
traces[0] = traces[0][1:]
|
|
traces[1] = traces[1][1:]
|
|
traces[2] = traces[2][1:]
|
|
traces[3] = traces[3][1:]
|
|
traces[4] = traces[4][1:]
|
|
traces[5] = traces[5][1:]
|
|
|
|
i /= 1000.0
|
|
x = list(range(max(n - max_bins, 0) * int(i), n * int(i), max(int(i), 1)))
|
|
|
|
lay = dict(
|
|
plot_bgcolor = '#082255',
|
|
paper_bgcolor = '#082255',
|
|
font={"color": "#fff"},
|
|
xaxis = {
|
|
'title': 'Time (sec)',
|
|
"showgrid": False,
|
|
"showline": False,
|
|
"fixedrange": True,
|
|
"tickmode": 'linear',
|
|
"dtick": i,
|
|
},
|
|
yaxis = {
|
|
'title': 'Flow Count',
|
|
"showgrid": False,
|
|
"showline": False,
|
|
"zeroline": False,
|
|
"fixedrange": True,
|
|
"tickmode": 'linear',
|
|
"dtick": 10,
|
|
},
|
|
autosize=True,
|
|
bargap=0.01,
|
|
bargroupgap=0,
|
|
hovermode="closest",
|
|
margin = {'b': 0, 'l': 0, 'r': 0, 't': 0, 'pad': 0},
|
|
legend = {'borderwidth': 0},
|
|
)
|
|
|
|
fig = go.Figure(layout=lay)
|
|
fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='#007ACE', zeroline=True, zerolinewidth=1)
|
|
fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='#007ACE', zeroline=True, zerolinewidth=1)
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[0],
|
|
name='Current Active Flows',
|
|
))
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[1],
|
|
name='Current Risky Flows',
|
|
))
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[2],
|
|
name='Current Midstream Flows',
|
|
))
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[3],
|
|
name='Current Guessed Flows',
|
|
))
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[4],
|
|
name='Current Not Detected Flows',
|
|
))
|
|
fig.add_trace(go.Scatter(
|
|
x=x,
|
|
y=traces[5],
|
|
name='Current Unclassified Flows',
|
|
))
|
|
|
|
return [fig, traces]
|
|
|
|
def web_worker(mp_shared_flow_dict):
|
|
global shared_flow_dict
|
|
|
|
shared_flow_dict = mp_shared_flow_dict
|
|
|
|
app.run_server(debug=False)
|