Completed
Push — master ( 17da33...be8f19 )
by Kenny
03:14
created

Memcache.__init__()   A

Complexity

Conditions 1

Size

Total Lines 22

Duplication

Lines 22
Ratio 100 %

Importance

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