codekingpro/portable-devtools
114k
1"""
2"""
3
4# Created on 2014.03.15
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2013 - 2020 Giovanni Cannata
9#
10# This file is part of ldap3.
11#
12# ldap3 is free software: you can redistribute it and/or modify
13# it under the terms of the GNU Lesser General Public License as published
14# by the Free Software Foundation, either version 3 of the License, or
15# (at your option) any later version.
16#
17# ldap3 is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with ldap3 in the COPYING and COPYING.LESSER files.
24# If not, see <http://www.gnu.org/licenses/>.
25
26from datetime import datetime, timedelta
27from os import linesep
28
29from .exceptions import LDAPMetricsError
30from ..utils.log import log, log_enabled, ERROR, BASIC
31
32
33class ConnectionUsage(object):
34 """
35 Collect statistics on connection usage
36 """
37
38 def reset(self):
39 self.open_sockets = 0
40 self.closed_sockets = 0
41 self.wrapped_sockets = 0
42 self.bytes_transmitted = 0
43 self.bytes_received = 0
44 self.messages_transmitted = 0
45 self.messages_received = 0
46 self.operations = 0
47 self.abandon_operations = 0
48 self.add_operations = 0
49 self.bind_operations = 0
50 self.compare_operations = 0
51 self.delete_operations = 0
52 self.extended_operations = 0
53 self.modify_operations = 0
54 self.modify_dn_operations = 0
55 self.search_operations = 0
56 self.unbind_operations = 0
57 self.referrals_received = 0
58 self.referrals_followed = 0
59 self.referrals_connections = 0
60 self.restartable_failures = 0
61 self.restartable_successes = 0
62 self.servers_from_pool = 0
63 if log_enabled(BASIC):
64 log(BASIC, 'reset usage metrics')
65
66 def __init__(self):
67 self.initial_connection_start_time = None
68 self.open_socket_start_time = None
69 self.connection_stop_time = None
70 self.last_transmitted_time = None
71 self.last_received_time = None
72 self.open_sockets = 0
73 self.closed_sockets = 0
74 self.wrapped_sockets = 0
75 self.bytes_transmitted = 0
76 self.bytes_received = 0
77 self.messages_transmitted = 0
78 self.messages_received = 0
79 self.operations = 0
80 self.abandon_operations = 0
81 self.add_operations = 0
82 self.bind_operations = 0
83 self.compare_operations = 0
84 self.delete_operations = 0
85 self.extended_operations = 0
86 self.modify_operations = 0
87 self.modify_dn_operations = 0
88 self.search_operations = 0
89 self.unbind_operations = 0
90 self.referrals_received = 0
91 self.referrals_followed = 0
92 self.referrals_connections = 0
93 self.restartable_failures = 0
94 self.restartable_successes = 0
95 self.servers_from_pool = 0
96
97 if log_enabled(BASIC):
98 log(BASIC, 'instantiated Usage object')
99
100 def __repr__(self):
101 r = 'Connection Usage:' + linesep
102 r += ' Time: [elapsed: ' + str(self.elapsed_time) + ']' + linesep
103 r += ' Initial start time: ' + (str(self.initial_connection_start_time.isoformat()) if self.initial_connection_start_time else '') + linesep
104 r += ' Open socket time: ' + (str(self.open_socket_start_time.isoformat()) if self.open_socket_start_time else '') + linesep
105 r += ' Last transmitted time: ' + (str(self.last_transmitted_time.isoformat()) if self.last_transmitted_time else '') + linesep
106 r += ' Last received time: ' + (str(self.last_received_time.isoformat()) if self.last_received_time else '') + linesep
107 r += ' Close socket time: ' + (str(self.connection_stop_time.isoformat()) if self.connection_stop_time else '') + linesep
108 r += ' Server:' + linesep
109 r += ' Servers from pool: ' + str(self.servers_from_pool) + linesep
110 r += ' Sockets open: ' + str(self.open_sockets) + linesep
111 r += ' Sockets closed: ' + str(self.closed_sockets) + linesep
112 r += ' Sockets wrapped: ' + str(self.wrapped_sockets) + linesep
113 r += ' Bytes: ' + str(self.bytes_transmitted + self.bytes_received) + linesep
114 r += ' Transmitted: ' + str(self.bytes_transmitted) + linesep
115 r += ' Received: ' + str(self.bytes_received) + linesep
116 r += ' Messages: ' + str(self.messages_transmitted + self.messages_received) + linesep
117 r += ' Transmitted: ' + str(self.messages_transmitted) + linesep
118 r += ' Received: ' + str(self.messages_received) + linesep
119 r += ' Operations: ' + str(self.operations) + linesep
120 r += ' Abandon: ' + str(self.abandon_operations) + linesep
121 r += ' Bind: ' + str(self.bind_operations) + linesep
122 r += ' Add: ' + str(self.add_operations) + linesep
123 r += ' Compare: ' + str(self.compare_operations) + linesep
124 r += ' Delete: ' + str(self.delete_operations) + linesep
125 r += ' Extended: ' + str(self.extended_operations) + linesep
126 r += ' Modify: ' + str(self.modify_operations) + linesep
127 r += ' ModifyDn: ' + str(self.modify_dn_operations) + linesep
128 r += ' Search: ' + str(self.search_operations) + linesep
129 r += ' Unbind: ' + str(self.unbind_operations) + linesep
130 r += ' Referrals: ' + linesep
131 r += ' Received: ' + str(self.referrals_received) + linesep
132 r += ' Followed: ' + str(self.referrals_followed) + linesep
133 r += ' Connections: ' + str(self.referrals_connections) + linesep
134 r += ' Restartable tries: ' + str(self.restartable_failures + self.restartable_successes) + linesep
135 r += ' Failed restarts: ' + str(self.restartable_failures) + linesep
136 r += ' Successful restarts: ' + str(self.restartable_successes) + linesep
137 return r
138
139 def __str__(self):
140 return self.__repr__()
141
142 def __iadd__(self, other):
143 if not isinstance(other, ConnectionUsage):
144 raise LDAPMetricsError('unable to add to ConnectionUsage')
145
146 self.open_sockets += other.open_sockets
147 self.closed_sockets += other.closed_sockets
148 self.wrapped_sockets += other.wrapped_sockets
149 self.bytes_transmitted += other.bytes_transmitted
150 self.bytes_received += other.bytes_received
151 self.messages_transmitted += other.messages_transmitted
152 self.messages_received += other.messages_received
153 self.operations += other.operations
154 self.abandon_operations += other.abandon_operations
155 self.add_operations += other.add_operations
156 self.bind_operations += other.bind_operations
157 self.compare_operations += other.compare_operations
158 self.delete_operations += other.delete_operations
159 self.extended_operations += other.extended_operations
160 self.modify_operations += other.modify_operations
161 self.modify_dn_operations += other.modify_dn_operations
162 self.search_operations += other.search_operations
163 self.unbind_operations += other.unbind_operations
164 self.referrals_received += other.referrals_received
165 self.referrals_followed += other.referrals_followed
166 self.referrals_connections += other.referrals_connections
167 self.restartable_failures += other.restartable_failures
168 self.restartable_successes += other.restartable_successes
169 self.servers_from_pool += other.servers_from_pool
170 return self
171
172 def update_transmitted_message(self, message, length):
173 self.last_transmitted_time = datetime.now()
174 self.bytes_transmitted += length
175 self.operations += 1
176 self.messages_transmitted += 1
177 if message['type'] == 'abandonRequest':
178 self.abandon_operations += 1
179 elif message['type'] == 'addRequest':
180 self.add_operations += 1
181 elif message['type'] == 'bindRequest':
182 self.bind_operations += 1
183 elif message['type'] == 'compareRequest':
184 self.compare_operations += 1
185 elif message['type'] == 'delRequest':
186 self.delete_operations += 1
187 elif message['type'] == 'extendedReq':
188 self.extended_operations += 1
189 elif message['type'] == 'modifyRequest':
190 self.modify_operations += 1
191 elif message['type'] == 'modDNRequest':
192 self.modify_dn_operations += 1
193 elif message['type'] == 'searchRequest':
194 self.search_operations += 1
195 elif message['type'] == 'unbindRequest':
196 self.unbind_operations += 1
197 else:
198 if log_enabled(ERROR):
199 log(ERROR, 'unable to collect usage for unknown message type <%s>', message['type'])
200 raise LDAPMetricsError('unable to collect usage for unknown message type')
201
202 def update_received_message(self, length):
203 self.last_received_time = datetime.now()
204 self.bytes_received += length
205 self.messages_received += 1
206
207 def start(self, reset=True):
208 if reset:
209 self.reset()
210 self.open_socket_start_time = datetime.now()
211 self.connection_stop_time = None
212 if not self.initial_connection_start_time:
213 self.initial_connection_start_time = self.open_socket_start_time
214
215 if log_enabled(BASIC):
216 log(BASIC, 'start collecting usage metrics')
217
218 def stop(self):
219 if self.open_socket_start_time:
220 self.connection_stop_time = datetime.now()
221 if log_enabled(BASIC):
222 log(BASIC, 'stop collecting usage metrics')
223
224 @property
225 def elapsed_time(self):
226 if self.connection_stop_time:
227 return self.connection_stop_time - self.open_socket_start_time
228 else:
229 return (datetime.now() - self.open_socket_start_time) if self.open_socket_start_time else timedelta(0)
230 