Total Complexity | 21 |
Total Lines | 190 |
Duplicated Lines | 28.95 % |
Changes | 1 | ||
Bugs | 1 | Features | 1 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | # -*- coding: utf-8 -*- |
||
20 | class Memcache(plumd.plugins.Reader): |
||
21 | """Plugin to record memcache stats.""" |
||
22 | |||
23 | STAT_CMD = "stats\n" |
||
24 | RECV_SIZE = 4096 |
||
25 | |||
26 | # default config values |
||
27 | defaults = { |
||
28 | 'poll.interval': 10, |
||
29 | 'gauges': [ |
||
30 | "auth_cmds", |
||
31 | "auth_errors", |
||
32 | "bytes", |
||
33 | "bytes_read", |
||
34 | "bytes_written", |
||
35 | "cas_badval", |
||
36 | "cas_hits", |
||
37 | "cas_misses", |
||
38 | "cmd_flush", |
||
39 | "cmd_get", |
||
40 | "cmd_set", |
||
41 | "cmd_touch", |
||
42 | "connection_structures", |
||
43 | "conn_yields", |
||
44 | "curr_connections", |
||
45 | "curr_items", |
||
46 | "decr_hits", |
||
47 | "decr_misses", |
||
48 | "delete_hits", |
||
49 | "delete_misses", |
||
50 | "evicted_unfetched", |
||
51 | "evictions", |
||
52 | "expired_unfetched", |
||
53 | "get_hits", |
||
54 | "get_misses", |
||
55 | "hash_bytes", |
||
56 | "hash_is_expanding", |
||
57 | "hash_power_level", |
||
58 | "incr_hits", |
||
59 | "incr_misses", |
||
60 | "limit_maxbytes", |
||
61 | "listen_disabled_num", |
||
62 | "reclaimed", |
||
63 | "reserved_fds", |
||
64 | "rusage_system", |
||
65 | "rusage_user", |
||
66 | "threads", |
||
67 | "total_connections", |
||
68 | "total_items", |
||
69 | "touch_hits", |
||
70 | "touch_misses", |
||
71 | "uptime" |
||
72 | ], |
||
73 | 'rates': [], |
||
74 | 'host': '127.0.0.1', # memcache server hostname/ip |
||
75 | 'port': 11211, # memcache server port |
||
76 | 'socket': None, # use tcp or unix domain socket |
||
77 | 'timeout': 10 # connection timeouts |
||
78 | } |
||
79 | |||
80 | View Code Duplication | def __init__(self, log, config): |
|
1 ignored issue
–
show
|
|||
81 | """Plugin to record memcache stats. |
||
82 | |||
83 | :param log: A logger |
||
84 | :type log: logging.RootLogger |
||
85 | :param config: a plumd.config.Conf configuration helper instance. |
||
86 | :type config: plumd.config.Conf |
||
87 | """ |
||
88 | super(Memcache, self).__init__(log, config) |
||
89 | self.config.defaults(Memcache.defaults) |
||
90 | |||
91 | # metrics to record |
||
92 | self.gauges = self.config.get('gauges') |
||
93 | self.rates = self.config.get('rates') |
||
94 | |||
95 | # memcached connection - either unix socket or tcp |
||
96 | spath = self.config.get('socket') |
||
97 | if spath is None: |
||
98 | host = self.config.get('host') |
||
99 | port = self.config.get('port') |
||
100 | self.addr = (host, port) |
||
101 | self.sfamily = socket.AF_INET |
||
102 | else: |
||
103 | self.addr = spath |
||
104 | self.sfamily = socket.AF_UNIX |
||
105 | |||
106 | self.socket = None |
||
107 | self.timeout = config.get('timeout') |
||
108 | self.calc = Differential() |
||
109 | |||
110 | |||
111 | def poll(self): |
||
112 | """Query memcache for stats. |
||
113 | |||
114 | :rtype: ResultSet |
||
115 | """ |
||
116 | result = plumd.Result("memcache") |
||
117 | |||
118 | name = self.name |
||
119 | stats = self.get_stats() |
||
120 | ts = time.time() |
||
121 | |||
122 | # record gauges |
||
123 | for stat in self.gauges: |
||
124 | if stat in stats: |
||
125 | mname = "{0}.{1}".format(name, stat) |
||
126 | result.add(plumd.Float(mname, stats[stat])) |
||
127 | |||
128 | # record rates |
||
129 | for stat in self.rates: |
||
130 | if stat in stats: |
||
131 | mname = "{0}.{1}".format(name, stat) |
||
132 | mval = self.calc.per_second(mname, float(stats[stat]), ts) |
||
133 | result.add(plumd.Float(mname, mval)) |
||
134 | |||
135 | return plumd.ResultSet([result]) |
||
136 | |||
137 | |||
138 | def get_stats(self): |
||
139 | """Request and read stats from memcache socket.""" |
||
140 | stats = {} |
||
141 | |||
142 | if not self.socket and not self.connect(): |
||
143 | return {} |
||
144 | |||
145 | try: |
||
146 | if PY3: |
||
147 | self.socket.sendall(bytes(Memcache.STAT_CMD, 'utf8')) |
||
148 | else: |
||
149 | self.socket.sendall(Memcache.STAT_CMD) |
||
150 | |||
151 | st_str = self.socket.recv(Memcache.RECV_SIZE) |
||
152 | self.log.debug("Memcached: read: {0}".format(st_str)) |
||
153 | |||
154 | for line in st_str.split("\n"): |
||
155 | vals = line.split() |
||
156 | if len(vals) != 3: |
||
157 | continue |
||
158 | stype, sname, sval = vals |
||
159 | if stype == "STAT": |
||
160 | msg = "Memcached: {0} = {1}" |
||
161 | self.log.debug(msg.format(sname, sval)) |
||
162 | stats[sname] = sval |
||
163 | |||
164 | except Exception as e: |
||
165 | msg = "Memcached: {0}: poll: exception: {1}" |
||
166 | self.log.error(msg.format(self.addr, e)) |
||
167 | self.disconnect() |
||
168 | |||
169 | return stats |
||
170 | |||
171 | |||
172 | View Code Duplication | def connect(self): |
|
1 ignored issue
–
show
|
|||
173 | """Connect to memcached, returns True if sucessful, False otherwise. |
||
174 | |||
175 | :rtype: bool |
||
176 | """ |
||
177 | self.log.debug("Memcached: connecting: {0}".format(self.addr)) |
||
178 | if self.socket: |
||
179 | self.disconnect() |
||
180 | try: |
||
181 | # create the socket |
||
182 | self.socket = socket.socket(self.sfamily, |
||
183 | socket.SOCK_STREAM) |
||
184 | # set timeout for socket operations |
||
185 | self.socket.settimeout(self.timeout) |
||
186 | # connect |
||
187 | self.socket.connect(self.addr) |
||
188 | # log and return |
||
189 | msg = "Memcached: connected: {0}" |
||
190 | self.log.info(msg.format(self.addr)) |
||
191 | return True |
||
192 | except Exception as e: |
||
193 | # log exception, ensure cleanup is done (disconnect) |
||
194 | msg = "Memcached: {0}: connect: excception: {1}" |
||
195 | self.log.error(msg.format(self.addr, e)) |
||
196 | return False |
||
197 | return False |
||
198 | |||
199 | |||
200 | def disconnect(self): |
||
201 | """Severe the memcached connection.""" |
||
202 | if self.socket: |
||
203 | try: |
||
204 | self.socket.close() |
||
205 | self.socket = None |
||
206 | except Exception as e: |
||
207 | msg = "Memcached: dicsonnect: exception {0}".format(e) |
||
208 | self.log.error(msg) |
||
209 | self.socket = None |
||
210 |