Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
蜕变的菜鸟
glances
提交
34a500e3
G
glances
项目概览
蜕变的菜鸟
/
glances
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
glances
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
34a500e3
编写于
3月 31, 2016
作者:
N
nicolargo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
CPU additionnal stats monitoring: Context switch, Interrupts... (issue #810)
上级
4e9cf18c
变更
10
显示空白变更内容
内联
并排
Showing
10 changed file
with
175 addition
and
66 deletion
+175
-66
NEWS
NEWS
+1
-0
conf/glances.conf
conf/glances.conf
+5
-0
docs/_static/cpu-wide.png
docs/_static/cpu-wide.png
+0
-0
docs/aoa/cpu.rst
docs/aoa/cpu.rst
+16
-2
docs/man/glances.1
docs/man/glances.1
+1
-1
glances/plugins/glances_cpu.py
glances/plugins/glances_cpu.py
+138
-54
glances/plugins/glances_diskio.py
glances/plugins/glances_diskio.py
+1
-1
glances/plugins/glances_load.py
glances/plugins/glances_load.py
+1
-1
glances/plugins/glances_plugin.py
glances/plugins/glances_plugin.py
+4
-0
glances/plugins/glances_quicklook.py
glances/plugins/glances_quicklook.py
+8
-7
未找到文件。
NEWS
浏览文件 @
34a500e3
...
@@ -7,6 +7,7 @@ Version 2.7
...
@@ -7,6 +7,7 @@ Version 2.7
Enhancements and new features:
Enhancements and new features:
* CPU additionnal stats monitoring: Context switch, Interrupts... (issue #810)
* [Folders] Differentiate permission issue and non-existence of a directory (issue #828)
* [Folders] Differentiate permission issue and non-existence of a directory (issue #828)
* [Web UI] add cpu name in quicklook plugin (issue #825)
* [Web UI] add cpu name in quicklook plugin (issue #825)
...
...
conf/glances.conf
浏览文件 @
34a500e3
...
@@ -28,6 +28,11 @@ steal_careful=50
...
@@ -28,6 +28,11 @@ steal_careful=50
steal_warning
=
70
steal_warning
=
70
steal_critical
=
90
steal_critical
=
90
#steal_log=True
#steal_log=True
# Context switch limit per core / second
# For example, if you have 2 Core, critical limit will be 28000/sec
ctx_switches_careful
=
10000
ctx_switches_warning
=
12000
ctx_switches_critical
=
14000
[
percpu
]
[
percpu
]
# Define CPU thresholds in %
# Define CPU thresholds in %
...
...
docs/_static/cpu-wide.png
查看替换文件 @
4e9cf18c
浏览文件 @
34a500e3
14.8 KB
|
W:
|
H:
29.6 KB
|
W:
|
H:
2-up
Swipe
Onion skin
docs/aoa/cpu.rst
浏览文件 @
34a500e3
...
@@ -3,8 +3,8 @@
...
@@ -3,8 +3,8 @@
CPU
CPU
===
===
The CPU stats are shown as a percentage
and for the configured refresh
The CPU stats are shown as a percentage
or value and for the configured
time. The total CPU usage is displayed on the first line.
refresh
time. The total CPU usage is displayed on the first line.
.. image:: ../_static/cpu.png
.. image:: ../_static/cpu.png
...
@@ -13,6 +13,20 @@ displayed.
...
@@ -13,6 +13,20 @@ displayed.
.. image:: ../_static/cpu-wide.png
.. image:: ../_static/cpu-wide.png
CPU stats description:
* user: percent time spent in user space
* system: percent time spent in kernel space
* idle: percent of CPU used by any program
* nice: percent time occupied by user level processes with a positive nice value
* irq: percent time spent servicing/handling hardware/software interrupts
* iowait: percent time spent in wait (on disk)
* steal: percent time in involuntary wait by virtual cpu while hypervisor is servicing another processor/virtual machine
* ctx_sw: number of context switches (voluntary + involuntary) per second
* inter: number of interrupts per second
* sw_inter: number of software interrupts per second. Always set to 0 on Windows and SunOS.
* syscal: number of system calls per second. Do not displayed on Linux (always 0).
To switch to per-CPU stats, just hit the ``1`` key:
To switch to per-CPU stats, just hit the ``1`` key:
.. image:: ../_static/per-cpu.png
.. image:: ../_static/per-cpu.png
...
...
docs/man/glances.1
浏览文件 @
34a500e3
.\" Man page generated from reStructuredText.
.\" Man page generated from reStructuredText.
.
.
.TH "GLANCES" "1" "March
28
, 2016" "2.7_BETA" "Glances"
.TH "GLANCES" "1" "March
31
, 2016" "2.7_BETA" "Glances"
.SH NAME
.SH NAME
glances \- An eye on your system
glances \- An eye on your system
.
.
...
...
glances/plugins/glances_cpu.py
浏览文件 @
34a500e3
...
@@ -19,8 +19,11 @@
...
@@ -19,8 +19,11 @@
"""CPU plugin."""
"""CPU plugin."""
from
glances.timer
import
getTimeSinceLastUpdate
from
glances.compat
import
iterkeys
from
glances.compat
import
iterkeys
from
glances.cpu_percent
import
cpu_percent
from
glances.cpu_percent
import
cpu_percent
from
glances.globals
import
LINUX
from
glances.plugins.glances_core
import
Plugin
as
CorePlugin
from
glances.plugins.glances_plugin
import
GlancesPlugin
from
glances.plugins.glances_plugin
import
GlancesPlugin
import
psutil
import
psutil
...
@@ -65,6 +68,12 @@ class Plugin(GlancesPlugin):
...
@@ -65,6 +68,12 @@ class Plugin(GlancesPlugin):
# Init stats
# Init stats
self
.
reset
()
self
.
reset
()
# Call CorePlugin in order to display the core number
try
:
self
.
nb_log_core
=
CorePlugin
(
args
=
self
.
args
).
update
()[
"log"
]
except
Exception
:
self
.
nb_log_core
=
1
def
reset
(
self
):
def
reset
(
self
):
"""Reset/init the stats."""
"""Reset/init the stats."""
self
.
stats
=
{}
self
.
stats
=
{}
...
@@ -75,9 +84,23 @@ class Plugin(GlancesPlugin):
...
@@ -75,9 +84,23 @@ class Plugin(GlancesPlugin):
# Reset stats
# Reset stats
self
.
reset
()
self
.
reset
()
# Grab CPU stats using psutil's cpu_percent and cpu_times_percent
# Grab stats into self.stats
# methods
if
self
.
input_method
==
'local'
:
if
self
.
input_method
==
'local'
:
self
.
update_local
()
elif
self
.
input_method
==
'snmp'
:
self
.
update_snmp
()
# Update the history list
self
.
update_stats_history
()
# Update the view
self
.
update_views
()
return
self
.
stats
def
update_local
(
self
):
"""Update CPU stats using PSUtil."""
# Grab CPU stats using psutil's cpu_percent and cpu_times_percent
# Get all possible values for CPU stats: user, system, idle,
# Get all possible values for CPU stats: user, system, idle,
# nice (UNIX), iowait (Linux), irq (Linux, FreeBSD), steal (Linux 2.6.11+)
# nice (UNIX), iowait (Linux), irq (Linux, FreeBSD), steal (Linux 2.6.11+)
# The following stats are returned by the API but not displayed in the UI:
# The following stats are returned by the API but not displayed in the UI:
...
@@ -88,7 +111,41 @@ class Plugin(GlancesPlugin):
...
@@ -88,7 +111,41 @@ class Plugin(GlancesPlugin):
'irq'
,
'softirq'
,
'steal'
,
'guest'
,
'guest_nice'
]:
'irq'
,
'softirq'
,
'steal'
,
'guest'
,
'guest_nice'
]:
if
hasattr
(
cpu_times_percent
,
stat
):
if
hasattr
(
cpu_times_percent
,
stat
):
self
.
stats
[
stat
]
=
getattr
(
cpu_times_percent
,
stat
)
self
.
stats
[
stat
]
=
getattr
(
cpu_times_percent
,
stat
)
elif
self
.
input_method
==
'snmp'
:
# Additionnal CPU stats (number of events / not as a %)
# ctx_switches: number of context switches (voluntary + involuntary) per second
# interrupts: number of interrupts per second
# soft_interrupts: number of software interrupts per second. Always set to 0 on Windows and SunOS.
# syscalls: number of system calls since boot. Always set to 0 on Linux.
try
:
cpu_stats
=
psutil
.
cpu_stats
()
except
AttributeError
:
# cpu_stats only available with PSUtil 4.1 or +
pass
else
:
# By storing time data we enable Rx/s and Tx/s calculations in the
# XML/RPC API, which would otherwise be overly difficult work
# for users of the API
time_since_update
=
getTimeSinceLastUpdate
(
'cpu'
)
# Previous CPU stats are stored in the cpu_stats_old variable
if
not
hasattr
(
self
,
'cpu_stats_old'
):
# First call, we init the cpu_stats_old var
self
.
cpu_stats_old
=
cpu_stats
else
:
for
stat
in
cpu_stats
.
_fields
:
self
.
stats
[
stat
]
=
getattr
(
cpu_stats
,
stat
)
-
getattr
(
self
.
cpu_stats_old
,
stat
)
self
.
stats
[
'time_since_update'
]
=
time_since_update
# Core number is needed to compute the CTX switch limit
self
.
stats
[
'cpucore'
]
=
self
.
nb_log_core
# Save stats to compute next step
self
.
cpu_stats_old
=
cpu_stats
def
update_snmp
(
self
):
"""Update CPU stats using SNMP."""
# Update stats using SNMP
# Update stats using SNMP
if
self
.
short_system_name
in
(
'windows'
,
'esxi'
):
if
self
.
short_system_name
in
(
'windows'
,
'esxi'
):
# Windows or VMWare ESXi
# Windows or VMWare ESXi
...
@@ -131,14 +188,6 @@ class Plugin(GlancesPlugin):
...
@@ -131,14 +188,6 @@ class Plugin(GlancesPlugin):
self
.
stats
[
key
]
=
float
(
self
.
stats
[
key
])
self
.
stats
[
key
]
=
float
(
self
.
stats
[
key
])
self
.
stats
[
'total'
]
=
100
-
self
.
stats
[
'idle'
]
self
.
stats
[
'total'
]
=
100
-
self
.
stats
[
'idle'
]
# Update the history list
self
.
update_stats_history
()
# Update the view
self
.
update_views
()
return
self
.
stats
def
update_views
(
self
):
def
update_views
(
self
):
"""Update stats views."""
"""Update stats views."""
# Call the father's method
# Call the father's method
...
@@ -153,8 +202,12 @@ class Plugin(GlancesPlugin):
...
@@ -153,8 +202,12 @@ class Plugin(GlancesPlugin):
for
key
in
[
'steal'
,
'total'
]:
for
key
in
[
'steal'
,
'total'
]:
if
key
in
self
.
stats
:
if
key
in
self
.
stats
:
self
.
views
[
key
][
'decoration'
]
=
self
.
get_alert
(
self
.
stats
[
key
],
header
=
key
)
self
.
views
[
key
][
'decoration'
]
=
self
.
get_alert
(
self
.
stats
[
key
],
header
=
key
)
# Alert only but depend on Core number
for
key
in
[
'ctx_switches'
]:
if
key
in
self
.
stats
:
self
.
views
[
key
][
'decoration'
]
=
self
.
get_alert
(
self
.
stats
[
key
],
maximum
=
100
*
self
.
stats
[
'cpucore'
],
header
=
key
)
# Optional
# Optional
for
key
in
[
'nice'
,
'irq'
,
'iowait'
,
'steal'
]:
for
key
in
[
'nice'
,
'irq'
,
'iowait'
,
'steal'
,
'ctx_switches'
,
'interrupts'
,
'soft_interrupts'
,
'syscalls'
]:
if
key
in
self
.
stats
:
if
key
in
self
.
stats
:
self
.
views
[
key
][
'optional'
]
=
True
self
.
views
[
key
][
'optional'
]
=
True
...
@@ -171,6 +224,7 @@ class Plugin(GlancesPlugin):
...
@@ -171,6 +224,7 @@ class Plugin(GlancesPlugin):
# If user stat is not here, display only idle / total CPU usage (for
# If user stat is not here, display only idle / total CPU usage (for
# exemple on Windows OS)
# exemple on Windows OS)
idle_tag
=
'user'
not
in
self
.
stats
idle_tag
=
'user'
not
in
self
.
stats
# Header
# Header
msg
=
'{0:8}'
.
format
(
'CPU'
)
msg
=
'{0:8}'
.
format
(
'CPU'
)
ret
.
append
(
self
.
curse_add_line
(
msg
,
"TITLE"
))
ret
.
append
(
self
.
curse_add_line
(
msg
,
"TITLE"
))
...
@@ -187,6 +241,15 @@ class Plugin(GlancesPlugin):
...
@@ -187,6 +241,15 @@ class Plugin(GlancesPlugin):
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'nice'
,
option
=
'optional'
)))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'nice'
,
option
=
'optional'
)))
msg
=
'{0:>5}%'
.
format
(
self
.
stats
[
'nice'
])
msg
=
'{0:>5}%'
.
format
(
self
.
stats
[
'nice'
])
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'nice'
,
option
=
'optional'
)))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'nice'
,
option
=
'optional'
)))
# ctx_switches
if
'ctx_switches'
in
self
.
stats
:
msg
=
' {0:8}'
.
format
(
'ctx_sw:'
)
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'ctx_switches'
,
option
=
'optional'
)))
msg
=
'{0:>5}'
.
format
(
int
(
self
.
stats
[
'ctx_switches'
]
//
self
.
stats
[
'time_since_update'
]))
ret
.
append
(
self
.
curse_add_line
(
msg
,
self
.
get_views
(
key
=
'ctx_switches'
,
option
=
'decoration'
),
optional
=
self
.
get_views
(
key
=
'ctx_switches'
,
option
=
'optional'
)))
# New line
# New line
ret
.
append
(
self
.
curse_new_line
())
ret
.
append
(
self
.
curse_new_line
())
# User CPU
# User CPU
...
@@ -207,6 +270,13 @@ class Plugin(GlancesPlugin):
...
@@ -207,6 +270,13 @@ class Plugin(GlancesPlugin):
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'irq'
,
option
=
'optional'
)))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'irq'
,
option
=
'optional'
)))
msg
=
'{0:>5}%'
.
format
(
self
.
stats
[
'irq'
])
msg
=
'{0:>5}%'
.
format
(
self
.
stats
[
'irq'
])
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'irq'
,
option
=
'optional'
)))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'irq'
,
option
=
'optional'
)))
# interrupts
if
'interrupts'
in
self
.
stats
:
msg
=
' {0:8}'
.
format
(
'inter:'
)
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'interrupts'
,
option
=
'optional'
)))
msg
=
'{0:>5}'
.
format
(
int
(
self
.
stats
[
'interrupts'
]
//
self
.
stats
[
'time_since_update'
]))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'interrupts'
,
option
=
'optional'
)))
# New line
# New line
ret
.
append
(
self
.
curse_new_line
())
ret
.
append
(
self
.
curse_new_line
())
# System CPU
# System CPU
...
@@ -229,6 +299,13 @@ class Plugin(GlancesPlugin):
...
@@ -229,6 +299,13 @@ class Plugin(GlancesPlugin):
ret
.
append
(
self
.
curse_add_line
(
ret
.
append
(
self
.
curse_add_line
(
msg
,
self
.
get_views
(
key
=
'iowait'
,
option
=
'decoration'
),
msg
,
self
.
get_views
(
key
=
'iowait'
,
option
=
'decoration'
),
optional
=
self
.
get_views
(
key
=
'iowait'
,
option
=
'optional'
)))
optional
=
self
.
get_views
(
key
=
'iowait'
,
option
=
'optional'
)))
# soft_interrupts
if
'soft_interrupts'
in
self
.
stats
:
msg
=
' {0:8}'
.
format
(
'sw_int:'
)
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'soft_interrupts'
,
option
=
'optional'
)))
msg
=
'{0:>5}'
.
format
(
int
(
self
.
stats
[
'soft_interrupts'
]
//
self
.
stats
[
'time_since_update'
]))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'soft_interrupts'
,
option
=
'optional'
)))
# New line
# New line
ret
.
append
(
self
.
curse_new_line
())
ret
.
append
(
self
.
curse_new_line
())
# Idle CPU
# Idle CPU
...
@@ -245,6 +322,13 @@ class Plugin(GlancesPlugin):
...
@@ -245,6 +322,13 @@ class Plugin(GlancesPlugin):
ret
.
append
(
self
.
curse_add_line
(
ret
.
append
(
self
.
curse_add_line
(
msg
,
self
.
get_views
(
key
=
'steal'
,
option
=
'decoration'
),
msg
,
self
.
get_views
(
key
=
'steal'
,
option
=
'decoration'
),
optional
=
self
.
get_views
(
key
=
'steal'
,
option
=
'optional'
)))
optional
=
self
.
get_views
(
key
=
'steal'
,
option
=
'optional'
)))
# syscalls
# syscalls: number of system calls since boot. Always set to 0 on Linux. (do not display)
if
'syscalls'
in
self
.
stats
and
not
LINUX
:
msg
=
' {0:8}'
.
format
(
'syscal:'
)
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'syscalls'
,
option
=
'optional'
)))
msg
=
'{0:>5}'
.
format
(
int
(
self
.
stats
[
'syscalls'
]
//
self
.
stats
[
'time_since_update'
]))
ret
.
append
(
self
.
curse_add_line
(
msg
,
optional
=
self
.
get_views
(
key
=
'syscalls'
,
option
=
'optional'
)))
# Return the message with decoration
# Return the message with decoration
return
ret
return
ret
glances/plugins/glances_diskio.py
浏览文件 @
34a500e3
...
@@ -81,7 +81,7 @@ class Plugin(GlancesPlugin):
...
@@ -81,7 +81,7 @@ class Plugin(GlancesPlugin):
# Previous disk IO stats are stored in the diskio_old variable
# Previous disk IO stats are stored in the diskio_old variable
if
not
hasattr
(
self
,
'diskio_old'
):
if
not
hasattr
(
self
,
'diskio_old'
):
# First call, we init the
network
_old var
# First call, we init the
diskio
_old var
try
:
try
:
self
.
diskio_old
=
diskiocounters
self
.
diskio_old
=
diskiocounters
except
(
IOError
,
UnboundLocalError
):
except
(
IOError
,
UnboundLocalError
):
...
...
glances/plugins/glances_load.py
浏览文件 @
34a500e3
...
@@ -62,7 +62,7 @@ class Plugin(GlancesPlugin):
...
@@ -62,7 +62,7 @@ class Plugin(GlancesPlugin):
try
:
try
:
self
.
nb_log_core
=
CorePlugin
(
args
=
self
.
args
).
update
()[
"log"
]
self
.
nb_log_core
=
CorePlugin
(
args
=
self
.
args
).
update
()[
"log"
]
except
Exception
:
except
Exception
:
self
.
nb_log_core
=
0
self
.
nb_log_core
=
1
def
reset
(
self
):
def
reset
(
self
):
"""Reset/init the stats."""
"""Reset/init the stats."""
...
...
glances/plugins/glances_plugin.py
浏览文件 @
34a500e3
...
@@ -403,6 +403,8 @@ class GlancesPlugin(object):
...
@@ -403,6 +403,8 @@ class GlancesPlugin(object):
except
KeyError
:
except
KeyError
:
return
'DEFAULT'
return
'DEFAULT'
logger
.
debug
(
"{0} => ret = {1}"
.
format
(
stat_name
,
ret
))
# Manage log
# Manage log
log_str
=
""
log_str
=
""
if
self
.
__get_limit_log
(
stat_name
=
stat_name
,
default_action
=
log
):
if
self
.
__get_limit_log
(
stat_name
=
stat_name
,
default_action
=
log
):
...
@@ -455,6 +457,8 @@ class GlancesPlugin(object):
...
@@ -455,6 +457,8 @@ class GlancesPlugin(object):
# Exemple: network_careful
# Exemple: network_careful
limit
=
self
.
_limits
[
self
.
plugin_name
+
'_'
+
criticity
]
limit
=
self
.
_limits
[
self
.
plugin_name
+
'_'
+
criticity
]
# logger.debug("{0} {1} value is {2}".format(stat_name, criticity, limit))
# Return the limit
# Return the limit
return
limit
return
limit
...
...
glances/plugins/glances_quicklook.py
浏览文件 @
34a500e3
...
@@ -113,12 +113,13 @@ class Plugin(GlancesPlugin):
...
@@ -113,12 +113,13 @@ class Plugin(GlancesPlugin):
bar
=
Bar
(
max_width
)
bar
=
Bar
(
max_width
)
# Build the string message
# Build the string message
if
'cpu_name'
in
self
.
stats
:
if
'cpu_name'
in
self
.
stats
and
'cpu_hz_current'
in
self
.
stats
and
'cpu_hz'
in
self
.
stats
:
msg
=
'{0} - {1:.2f}/{2:.2f}GHz'
.
format
(
self
.
stats
[
'cpu_name'
],
msg
_name
=
'{0} - '
.
format
(
self
.
stats
[
'cpu_name'
])
self
.
_hz_to_ghz
(
self
.
stats
[
'cpu_hz_current'
]),
msg_freq
=
'{0:.2f}/{1:.2f}GHz'
.
format
(
self
.
_hz_to_ghz
(
self
.
stats
[
'cpu_hz_current'
]),
self
.
_hz_to_ghz
(
self
.
stats
[
'cpu_hz'
]))
self
.
_hz_to_ghz
(
self
.
stats
[
'cpu_hz'
]))
if
len
(
msg
)
-
6
<=
max_width
:
if
len
(
msg_name
+
msg_freq
)
-
6
<=
max_width
:
ret
.
append
(
self
.
curse_add_line
(
msg
))
ret
.
append
(
self
.
curse_add_line
(
msg_name
))
ret
.
append
(
self
.
curse_add_line
(
msg_freq
))
ret
.
append
(
self
.
curse_new_line
())
ret
.
append
(
self
.
curse_new_line
())
for
key
in
[
'cpu'
,
'mem'
,
'swap'
]:
for
key
in
[
'cpu'
,
'mem'
,
'swap'
]:
if
key
==
'cpu'
and
args
.
percpu
:
if
key
==
'cpu'
and
args
.
percpu
:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录