| Class | PhusionPassenger::AnalyticsLogger |
| In: |
lib/phusion_passenger/analytics_logger.rb
|
| Parent: | Object |
| RETRY_SLEEP | = | 0.2 |
| NETWORK_ERRORS | = | [Errno::EPIPE, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ENETDOWN, Errno::ENETUNREACH, Errno::ETIMEDOUT] |
| RANDOM_CHARS | = | ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] |
| max_connect_tries | [RW] | |
| reconnect_timeout | [RW] |
# File lib/phusion_passenger/analytics_logger.rb, line 150
150: def initialize(logging_agent_address, username, password, node_name)
151: @server_address = logging_agent_address
152: @username = username
153: @password = password
154: if node_name && !node_name.empty?
155: @node_name = node_name
156: else
157: @node_name = `hostname`.strip
158: end
159: @random_dev = File.open("/dev/urandom")
160:
161: # This mutex protects the following instance variables, but
162: # not the contents of @shared_data.
163: @mutex = Mutex.new
164:
165: @shared_data = SharedData.new
166: if @server_address && local_socket_address?(@server_address)
167: @max_connect_tries = 10
168: else
169: @max_connect_tries = 1
170: end
171: @reconnect_timeout = 60
172: @next_reconnect_time = Time.utc(1980, 1, 1)
173: end
# File lib/phusion_passenger/analytics_logger.rb, line 136
136: def self.new_from_options(options)
137: if options["analytics"] && options["logging_agent_address"]
138: return new(options["logging_agent_address"],
139: options["logging_agent_username"],
140: options["logging_agent_password_base64"].unpack('m').first,
141: options["node_name"])
142: else
143: return nil
144: end
145: end
# File lib/phusion_passenger/analytics_logger.rb, line 175
175: def clear_connection
176: @mutex.synchronize do
177: @shared_data.synchronize do
178: @random_dev = File.open("/dev/urandom") if @random_dev.closed?
179: @shared_data.unref
180: @shared_data = SharedData.new
181: end
182: end
183: end
# File lib/phusion_passenger/analytics_logger.rb, line 185
185: def close
186: @mutex.synchronize do
187: @shared_data.synchronize do
188: @random_dev.close
189: @shared_data.unref
190: @shared_data = nil
191: end
192: end
193: end
# File lib/phusion_passenger/analytics_logger.rb, line 245
245: def continue_transaction(txn_id, group_name, category = :requests, union_station_key = nil)
246: if !@server_address
247: return Log.new
248: elsif !txn_id || txn_id.empty?
249: raise ArgumentError, "Transaction ID may not be empty"
250: end
251:
252: Lock.new(@mutex).synchronize do |lock|
253: Lock.new(@shared_data.mutex).synchronize do |shared_data_lock|
254: try_count = 0
255: if current_time >= @next_reconnect_time
256: while try_count < @max_connect_tries
257: begin
258: connect if !connected?
259: @shared_data.client.write("openTransaction",
260: txn_id, group_name, "", category,
261: AnalyticsLogger.timestamp_string,
262: union_station_key,
263: true)
264: return Log.new(@shared_data, txn_id)
265: rescue Errno::ENOENT, *NETWORK_ERRORS
266: try_count += 1
267: disconnect(true)
268: shared_data_lock.reset(@shared_data.mutex, false)
269: lock.unlock
270: sleep RETRY_SLEEP if try_count < @max_connect_tries
271: lock.lock
272: shared_data_lock.lock
273: rescue Exception => e
274: disconnect
275: raise e
276: end
277: end
278: # Failed to connect.
279: DebugLogging.warn("Cannot connect to the logging agent (#{@server_address}); " +
280: "retrying in #{@reconnect_timeout} seconds.")
281: @next_reconnect_time = current_time + @reconnect_timeout
282: end
283: return Log.new
284: end
285: end
286: end
# File lib/phusion_passenger/analytics_logger.rb, line 195
195: def new_transaction(group_name, category = :requests, union_station_key = nil)
196: if !@server_address
197: return Log.new
198: elsif !group_name || group_name.empty?
199: raise ArgumentError, "Group name may not be empty"
200: end
201:
202: txn_id = (AnalyticsLogger.current_time.to_i / 60).to_s(36)
203: txn_id << "-#{random_token(11)}"
204: Lock.new(@mutex).synchronize do |lock|
205: Lock.new(@shared_data.mutex).synchronize do |shared_data_lock|
206: try_count = 0
207: if current_time >= @next_reconnect_time
208: while try_count < @max_connect_tries
209: begin
210: connect if !connected?
211: @shared_data.client.write("openTransaction",
212: txn_id, group_name, "", category,
213: AnalyticsLogger.timestamp_string,
214: union_station_key,
215: true,
216: true)
217: result = @shared_data.client.read
218: if result != ["ok"]
219: raise "Expected logging server to respond with 'ok', but got #{result.inspect} instead"
220: end
221: return Log.new(@shared_data, txn_id)
222: rescue Errno::ENOENT, *NETWORK_ERRORS
223: try_count += 1
224: disconnect(true)
225: shared_data_lock.reset(@shared_data.mutex, false)
226: lock.unlock
227: sleep RETRY_SLEEP if try_count < @max_connect_tries
228: lock.lock
229: shared_data_lock.lock
230: rescue Exception => e
231: disconnect
232: raise e
233: end
234: end
235: # Failed to connect.
236: DebugLogging.warn("Cannot connect to the logging agent (#{@server_address}); " +
237: "retrying in #{@reconnect_timeout} seconds.")
238: @next_reconnect_time = current_time + @reconnect_timeout
239: end
240: return Log.new
241: end
242: end
243: end