1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
# Copyright (C) 2014 Michele Baldessari <michele at acksyn.org>
# This file is part of the sos project: https://github.com/sosreport/sos
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# version 2 of the GNU General Public License.
#
# See the LICENSE file in the source distribution for further information.
from socket import gethostname
from sos.report.plugins import Plugin, RedHatPlugin, DebianPlugin, PluginOpt
class Pcp(Plugin, RedHatPlugin, DebianPlugin):
short_desc = 'Performance Co-Pilot data'
plugin_name = 'pcp'
profiles = ('system', 'performance')
packages = ('pcp',)
pcp_conffile = '/etc/pcp.conf'
# size-limit of PCP logger and manager data collected by default (MB)
option_list = [
PluginOpt('pmmgrlogs', default=100,
desc='size limit in MB of pmmgr logs'),
PluginOpt('pmloggerfiles', default=12,
desc='number of pmlogger files to collect')
]
pcp_sysconf_dir = None
pcp_var_dir = None
pcp_log_dir = None
pcp_hostname = ''
def pcp_parse_conffile(self):
""" Parse PCP configuration """
try:
with open(self.pcp_conffile, "r", encoding='UTF-8') as pcpconf:
lines = pcpconf.readlines()
except IOError:
return False
env_vars = {}
for line in lines:
if line.startswith('#'):
continue
try:
(key, value) = line.strip().split('=')
env_vars[key] = value
except (ValueError, KeyError):
pass
try:
self.pcp_sysconf_dir = env_vars['PCP_SYSCONF_DIR']
self.pcp_var_dir = env_vars['PCP_VAR_DIR']
self.pcp_log_dir = env_vars['PCP_LOG_DIR']
except Exception: # pylint: disable=broad-except
# Fail if all three env variables are not found
return False
return True
def setup(self):
sizelimit = (None if self.get_option("all_logs")
else self.get_option("pmmgrlogs"))
countlimit = (None if self.get_option("all_logs")
else self.get_option("pmloggerfiles"))
if not self.pcp_parse_conffile():
self._log_warn(f"could not parse {self.pcp_conffile}")
return
# Add PCP_SYSCONF_DIR (/etc/pcp) and PCP_VAR_DIR (/var/lib/pcp/config)
# unconditionally. Obviously if someone messes up their /etc/pcp.conf
# in a ridiculous way (i.e. setting PCP_SYSCONF_DIR to '/') this will
# break badly.
var_conf_dir = self.path_join(self.pcp_var_dir, 'config')
self.add_copy_spec([
self.pcp_sysconf_dir,
self.pcp_conffile,
var_conf_dir
])
# We explicitly avoid /var/lib/pcp/config/{pmchart,pmlogconf,pmieconf,
# pmlogrewrite} as in 99% of the cases they are just copies from the
# rpms. It does not make up for a lot of size but it contains many
# files
self.add_forbidden_path([
self.path_join(var_conf_dir, 'pmchart'),
self.path_join(var_conf_dir, 'pmlogconf'),
self.path_join(var_conf_dir, 'pmieconf'),
self.path_join(var_conf_dir, 'pmlogrewrite')
])
# Take PCP_LOG_DIR/pmlogger/`hostname` + PCP_LOG_DIR/pmmgr/`hostname`
# The *default* directory structure for pmlogger is the following:
# Dir: PCP_LOG_DIR/pmlogger/HOST/ (we only collect the HOST data
# itself)
# - YYYYMMDD.HH.MM.{N,N.index,N.meta} N in [0,1,...]
# - Latest
# - pmlogger.{log,log.prior}
#
# Can be changed via configuration in PCP_SYSCONF_DIR/pmlogger/control
# As a default strategy, collect up to 100MB data from each dir.
# Can be overwritten either via pcp.pcplogsize option or all_logs.
self.pcp_hostname = gethostname()
# Make sure we only add the two dirs if hostname is set, otherwise
# we would collect everything
if self.pcp_hostname != '':
# collect pmmgr logs up to 'pmmgrlogs' size limit
path = self.path_join(self.pcp_log_dir, 'pmmgr',
self.pcp_hostname, '*')
self.add_copy_spec(path, sizelimit=sizelimit, tailit=False)
# collect newest pmlogger logs up to 'pmloggerfiles' count
files_collected = 0
path = self.path_join(self.pcp_log_dir, 'pmlogger',
self.pcp_hostname, '*')
pmlogger_ls = self.exec_cmd(f"ls -t1 {path}")
if pmlogger_ls['status'] == 0:
for line in pmlogger_ls['output'].splitlines():
self.add_copy_spec(line, sizelimit=0)
files_collected = files_collected + 1
if countlimit and files_collected == countlimit:
break
self.add_copy_spec([
# Collect PCP_LOG_DIR/pmcd and PCP_LOG_DIR/NOTICES
self.path_join(self.pcp_log_dir, 'pmcd'),
self.path_join(self.pcp_log_dir, 'NOTICES*'),
# Collect PCP_VAR_DIR/pmns
self.path_join(self.pcp_var_dir, 'pmns'),
# Also collect any other log and config files
# (as suggested by fche)
self.path_join(self.pcp_log_dir, '*/*.log*'),
self.path_join(self.pcp_log_dir, '*/*/*.log*'),
self.path_join(self.pcp_log_dir, '*/*/config*')
])
# Collect a summary for the current day
res = self.collect_cmd_output('pcp')
if res['status'] == 0:
for line in res['output'].splitlines():
if line.startswith(' pmlogger:'):
arc = line.split()[-1]
self.add_cmd_output(
f"pmstat -S 00:00 -T 23:59 -t 5m -x -a {arc}",
root_symlink="pmstat"
)
break
# vim: set et ts=4 sw=4 :
|