logplex-client 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +13 -0
- data/Makefile +34 -0
- data/README.md +117 -0
- data/bin/logplex +12 -0
- data/lib/logplex/channel.rb +144 -0
- data/lib/logplex/client/backends/http.rb +192 -0
- data/lib/logplex/client/cli.rb +219 -0
- data/lib/logplex/client/version.rb +6 -0
- data/lib/logplex/client.rb +80 -0
- data/lib/logplex/drain.rb +45 -0
- data/lib/logplex/emitter.rb +79 -0
- data/lib/logplex/event.rb +8 -0
- data/lib/logplex/namespace.rb +8 -0
- data/lib/logplex/session.rb +72 -0
- data/lib/logplex/token.rb +42 -0
- data/logplex-client.gemspec +30 -0
- data/spec/documentation_spec.rb +41 -0
- data/spec/logplex/channel_spec.rb +79 -0
- data/spec/logplex/client_spec.rb +40 -0
- data/spec/logplex/session_spec.rb +32 -0
- data/spec/spec_setup.rb +2 -0
- metadata +140 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Makefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
GEMSPEC=$(shell ls *.gemspec | head -1)
|
2
|
+
VERSION=$(shell ruby -rubygems -e 'puts Gem::Specification.load("$(GEMSPEC)").version')
|
3
|
+
PROJECT=$(shell ruby -rubygems -e 'puts Gem::Specification.load("$(GEMSPEC)").name')
|
4
|
+
GEM=$(PROJECT)-$(VERSION).gem
|
5
|
+
|
6
|
+
.PHONY: test
|
7
|
+
test:
|
8
|
+
bundle exec rspec
|
9
|
+
|
10
|
+
.PHONY: package
|
11
|
+
package: $(GEM)
|
12
|
+
|
13
|
+
# Always build the gem
|
14
|
+
.PHONY: $(GEM)
|
15
|
+
$(GEM):
|
16
|
+
gem build $(PROJECT).gemspec
|
17
|
+
|
18
|
+
showdocs:
|
19
|
+
yard server --plugin yard-tomdoc -r
|
20
|
+
|
21
|
+
clean:
|
22
|
+
-rm -r .yardoc/ doc/ *.gem
|
23
|
+
|
24
|
+
.PHONY: install
|
25
|
+
install: $(GEM)
|
26
|
+
gem install $<
|
27
|
+
|
28
|
+
# Publish to gemgate
|
29
|
+
.PHONY: publish
|
30
|
+
publish: APPNAME=gemgate-heroku-internal-gems
|
31
|
+
publish: URL=https://$(APPNAME).herokuapp.com
|
32
|
+
publish: GEMGATE_AUTH=$(shell heroku config -a $(APPNAME) | awk '/GEMGATE_AUTH/ { print $$NF }')
|
33
|
+
publish: $(GEM)
|
34
|
+
curl -F file=@$(GEM) -u $(GEMGATE_AUTH) $(URL)
|
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
## Logplex Client
|
2
|
+
|
3
|
+
### command line interface
|
4
|
+
|
5
|
+
What follows are examples.
|
6
|
+
|
7
|
+
```bash
|
8
|
+
# You must do this.
|
9
|
+
$ export LOGPLEX_URL=https://heroku:password@logplex.heroku.com
|
10
|
+
|
11
|
+
$ bin/logplex channels:create channel-blah
|
12
|
+
creating channel... done
|
13
|
+
channel id: 3858972
|
14
|
+
|
15
|
+
$ logplex channels:get 3858972
|
16
|
+
getting channel (3858972)... done
|
17
|
+
|
18
|
+
id: 3858972
|
19
|
+
no tokens
|
20
|
+
no drains
|
21
|
+
|
22
|
+
$ logplex channels:delete 3858972
|
23
|
+
deleting channel... done
|
24
|
+
|
25
|
+
$ logplex tokens:create 3858972 helloworld
|
26
|
+
creating token...
|
27
|
+
helloworld => t.7c55b81f-59b3-45bb-87b1-aefc0fd96a40
|
28
|
+
|
29
|
+
$ bin/logplex channels:get 3858972
|
30
|
+
getting channel (3858972)...done
|
31
|
+
|
32
|
+
id: 3858972
|
33
|
+
token: helloworld (t.7c55b81f-59b3-45bb-87b1-aefc0fd96a40)
|
34
|
+
no drains
|
35
|
+
|
36
|
+
$ bin/logplex channels:logs 3858972 --ps web.1
|
37
|
+
2012-03-22T00:12:47+00:00 app[web.1]: foo
|
38
|
+
2012-03-22T00:12:48+00:00 app[web.1]: bar
|
39
|
+
```
|
40
|
+
|
41
|
+
## Ruby Usage
|
42
|
+
|
43
|
+
### ruby api/usage docs
|
44
|
+
|
45
|
+
You can view the rubydoc for this project by running:
|
46
|
+
|
47
|
+
```bash
|
48
|
+
$ bundle install
|
49
|
+
$ make showdocs
|
50
|
+
```
|
51
|
+
|
52
|
+
Then point your browser at <http://localhost:8808/> to view the HTML version of
|
53
|
+
the API docs.
|
54
|
+
|
55
|
+
### Managing Logplex
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# Get a new client.
|
59
|
+
=> client = Logplex::Client.new("https://heroku:password@logplex.heroku.com")
|
60
|
+
|
61
|
+
# Create a named channel.
|
62
|
+
=> channel = client.create_channel("channel-blah")
|
63
|
+
|
64
|
+
# Get a known channel by id
|
65
|
+
=> channel = client.channel(1001)
|
66
|
+
|
67
|
+
# Destroy a channel
|
68
|
+
=> channel.destroy
|
69
|
+
|
70
|
+
# Create a named token on a channel
|
71
|
+
=> token = channel.create_token("app")
|
72
|
+
|
73
|
+
# Destroy a token
|
74
|
+
=> token.destroy
|
75
|
+
|
76
|
+
# Create a drain
|
77
|
+
=> drain = channel.create_drain
|
78
|
+
|
79
|
+
# Get a known drain by a drain id
|
80
|
+
=> drain = channel.drain(12345)
|
81
|
+
|
82
|
+
# Make the drain point at a specific syslog receiver:
|
83
|
+
=> drain.url = "syslog://example.com:1234/
|
84
|
+
|
85
|
+
# Destroy a drain
|
86
|
+
=> drain.destroy
|
87
|
+
```
|
88
|
+
|
89
|
+
### Writing to Logplex
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# Get an Emitter for writing logs using a token
|
93
|
+
=> emitter = token.emitter
|
94
|
+
|
95
|
+
# Writing an event
|
96
|
+
# Note, you must be running on the heroku platform for this to work as
|
97
|
+
# currently the port used by log transport into logplex is firewalled.
|
98
|
+
=> emitter.emit("processname", "message")
|
99
|
+
```
|
100
|
+
|
101
|
+
### Reading from Logplex
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
# Create a log session (for reading logs)
|
105
|
+
=> session = channel.session(:num => 10)
|
106
|
+
# or tail things
|
107
|
+
=> session = channel.session(:num => 10, :tail => true
|
108
|
+
|
109
|
+
# Read logs from a session
|
110
|
+
=> session.each_event do |event|
|
111
|
+
puts event
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
### Logplex HTTP API
|
116
|
+
|
117
|
+
https://logplex.herokuapp.com/
|
data/bin/logplex
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require "logplex/namespace"
|
2
|
+
require "logplex/drain"
|
3
|
+
require "logplex/session"
|
4
|
+
require "logplex/token"
|
5
|
+
|
6
|
+
# Operations on a Logplex::Channel:
|
7
|
+
# Delete a channel - DELETE /v2/channels/<channel>
|
8
|
+
# API> channel.destroy => nil
|
9
|
+
# Get channel info - GET /v2/channels/<channel>
|
10
|
+
# API> channel.tokens => [Token, Token, ...]
|
11
|
+
# API> channel.drains => [Drain, Drain, ...]
|
12
|
+
# Get a token with known name: (just a wrapper of 'channel.tokens')
|
13
|
+
# API> channel.token(name) => Token
|
14
|
+
# Create a token - POST /v2/channels/<channel>/tokens { "name": "the token name" }
|
15
|
+
# API> channel.create_token(name) => Token
|
16
|
+
# Create a drain - POST /v2/channels/<channel>/drains { "url": "syslog://.../" }
|
17
|
+
# API> channel.create_drain(url) => Drain
|
18
|
+
# Create a session - POST /v2/sessions { "channel_id": <channel>, ... }
|
19
|
+
# API> channel.create_session(:source => ..., ps => ..., num => ..., tail => ...) => Session
|
20
|
+
|
21
|
+
# Public: A logplex channel.
|
22
|
+
#
|
23
|
+
# You generally acquire one of these objects from
|
24
|
+
# Logplex::Client#create_channel or Logplex::Client#channel
|
25
|
+
class Logplex::Channel
|
26
|
+
# Public: initialize a channel object
|
27
|
+
#
|
28
|
+
# url - the url to logplex. See Logplex::Client#new for more info.
|
29
|
+
# channel_id - the channel id, should be a number.
|
30
|
+
#
|
31
|
+
# See also: Logplex::Client#create_channel and Logplex::Client#channel
|
32
|
+
def initialize(url, channel_id)
|
33
|
+
@url = url
|
34
|
+
@channel_id = channel_id
|
35
|
+
@backend = Logplex::Client::Backends::HTTP.new(@url)
|
36
|
+
end # def initialize
|
37
|
+
|
38
|
+
# Public: Destroy a channel.
|
39
|
+
#
|
40
|
+
# This will remove a channel from logplex as well as any associated tokens or
|
41
|
+
# drains.
|
42
|
+
#
|
43
|
+
# Returns nothing.
|
44
|
+
# Raises # TODO(sissel): What errors?
|
45
|
+
def destroy
|
46
|
+
@backend.delete_channel(@channel_id)
|
47
|
+
end # def destroy
|
48
|
+
|
49
|
+
# Public: Get the channel id.
|
50
|
+
#
|
51
|
+
# Returns the channel id.
|
52
|
+
def id
|
53
|
+
return @channel_id
|
54
|
+
end # def id
|
55
|
+
|
56
|
+
# Public: Get a list of tokens associated with this channel.
|
57
|
+
#
|
58
|
+
# Note: To create a token, see Logplex::Channel#create_token
|
59
|
+
#
|
60
|
+
# Returns an Array of Logplex::Tokens
|
61
|
+
# Raises # TODO(sissel): ???
|
62
|
+
def tokens
|
63
|
+
@info ||= @backend.get_channel(@channel_id)
|
64
|
+
result = @info
|
65
|
+
return result[:tokens].collect do |info|
|
66
|
+
Logplex::Token.new(@url, @channel_id, info[:name], info[:token])
|
67
|
+
end
|
68
|
+
end # def tokens
|
69
|
+
|
70
|
+
# Public: Get a list of drains associated with this channel.
|
71
|
+
#
|
72
|
+
# Note: To create a drain, see Logplex::Channel#create_drain
|
73
|
+
#
|
74
|
+
# Returns an Array of Logplex::Drains
|
75
|
+
# Raises # TODO(sissel): ???
|
76
|
+
def drains
|
77
|
+
@info ||= @backend.get_channel(@channel_id)
|
78
|
+
result = @info
|
79
|
+
return result[:drains].collect do |info|
|
80
|
+
Logplex::Drain.new(@url, @channel_id, info[:id], info[:token], info[:url])
|
81
|
+
end
|
82
|
+
end # def drains
|
83
|
+
|
84
|
+
# Public: Create a new token for this channel.
|
85
|
+
#
|
86
|
+
# name - a String name for this token. The name is meaningful and will
|
87
|
+
# appear in drain or session output.
|
88
|
+
#
|
89
|
+
# Returns a Logplex::Token
|
90
|
+
def create_token(name)
|
91
|
+
result = @backend.create_token(@channel_id, name)
|
92
|
+
return Logplex::Token.new(@url, @channel_id, result[:name], result[:token])
|
93
|
+
end # def create_token
|
94
|
+
|
95
|
+
# Public: Create a new drain for this channel.
|
96
|
+
#
|
97
|
+
# For information on what a drain is, see Logplex::Drain
|
98
|
+
#
|
99
|
+
# Returns a Logplex::Drain
|
100
|
+
# Raises # TODO(sissel): ???
|
101
|
+
def create_drain(url=nil)
|
102
|
+
# Just create the drain, don't add any URLs to it.
|
103
|
+
# API call /channels/[channel-id]/drains/tokens
|
104
|
+
result = @backend.create_drain(@channel_id, url)
|
105
|
+
return Logplex::Drain.new(@url, @channel_id, result[:id], result[:token], url)
|
106
|
+
end # def create_drain
|
107
|
+
|
108
|
+
# Public: Create a new session for this channel.
|
109
|
+
#
|
110
|
+
# For information on what a session is, see Logplex::Session
|
111
|
+
#
|
112
|
+
# settings - a hash containing:
|
113
|
+
# :source - the token name, like "app" or "heroku" (default: nil, optional)
|
114
|
+
# :ps - the RFC5424 process id, like "web.1" (default: nil, optional)
|
115
|
+
# :num - the number of events to retrieve (default: 40, optional)
|
116
|
+
# :tail - true if you wish to follow the live event stream
|
117
|
+
# (default: false, optional)
|
118
|
+
#
|
119
|
+
# Returns a Logplex::Session
|
120
|
+
# Raises # TODO(sissel): ???
|
121
|
+
def create_session(settings={})
|
122
|
+
settings = {
|
123
|
+
:num => 40,
|
124
|
+
:tail => false
|
125
|
+
}.merge(settings)
|
126
|
+
|
127
|
+
# Currently a bug(?) in logplex that if you specify 'num' = 0, you get all
|
128
|
+
# logs. TODO(sissel): If you specify '0.1' you get zero results, so use
|
129
|
+
# that hack to hide the '0' bug until the bug is fixed.
|
130
|
+
settings[:num] = 0.1 if settings[:num] == 0
|
131
|
+
|
132
|
+
# Here's what core does: https://github.com/heroku/core/blob/master/lib/logplex.rb#L12
|
133
|
+
# TODO(sissel): generate a random 'srv' id
|
134
|
+
server_id = rand(1000)
|
135
|
+
result = @backend.create_session(@channel_id, server_id, settings)
|
136
|
+
# the foo=bar& prefix is required because of some problem with haproxy or
|
137
|
+
# how we are using it to pin http requests to backends.
|
138
|
+
# Additionally, sesssions also don't need authentication, so strip that out.
|
139
|
+
url = URI.parse(@url + result[:url] + "?" + "foo=bar&srv=#{server_id}")
|
140
|
+
url.user = nil
|
141
|
+
url.password = nil
|
142
|
+
return Logplex::Session.new(url.to_s, settings)
|
143
|
+
end # def create_session
|
144
|
+
end # class Logplex::Channel
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require "multi_json"
|
2
|
+
require "restclient"
|
3
|
+
require "logplex/namespace"
|
4
|
+
require "openssl"
|
5
|
+
|
6
|
+
# A client implementation that speaks to the logplex http interface.
|
7
|
+
class Logplex::Client::Backends::HTTP
|
8
|
+
# Parent class of all Logplex-related HTTP errors.
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
# An error indicating the call to Logplex failed due to authentication
|
12
|
+
# problems.
|
13
|
+
class Unauthorized < Error; end
|
14
|
+
|
15
|
+
# An error indicating the call to Logplex failed due to a HTTP request
|
16
|
+
# returning 404.
|
17
|
+
class NotFound < Error; end
|
18
|
+
|
19
|
+
# A new logplex backend that uses HTTP
|
20
|
+
#
|
21
|
+
# url - (string) url to logplex, like "https://user:pass@logplex.example.com/"
|
22
|
+
def initialize(url)
|
23
|
+
@url = url
|
24
|
+
end # def initialize
|
25
|
+
|
26
|
+
# Returns a hash with form:
|
27
|
+
# {:channel_id=>3639270, :tokens=>[]}
|
28
|
+
def create_channel(name, tokens = [])
|
29
|
+
json_post("/channels", {:name => name, :tokens => tokens})
|
30
|
+
end # def create_channel
|
31
|
+
|
32
|
+
# Public: Creates a channel.
|
33
|
+
#
|
34
|
+
# Returns a hash of the json response in the form:
|
35
|
+
# {:channel_id=>3639270, :tokens=>[], :drains=>[]}
|
36
|
+
def get_channel(channel_id)
|
37
|
+
json_get("/v2/channels/#{channel_id}")
|
38
|
+
end # def get_channel
|
39
|
+
|
40
|
+
# Public: Deletes a channel
|
41
|
+
def delete_channel(channel_id)
|
42
|
+
delete("/v2/channels/#{channel_id}")
|
43
|
+
end # def delete_channel
|
44
|
+
|
45
|
+
# Public: Creates a token on a given channel
|
46
|
+
def create_token(channel_id, token_name)
|
47
|
+
json_post("/v2/channels/#{channel_id}/tokens", {:name => token_name})
|
48
|
+
end # def create_token
|
49
|
+
|
50
|
+
# Public: Creates a drain for a given channel.
|
51
|
+
def create_drain(channel_id, url)
|
52
|
+
json_post("/v2/channels/#{channel_id}/drains", :url => url)
|
53
|
+
end # def create_drain
|
54
|
+
|
55
|
+
# Public: Sets the drain url for a channel+drain.
|
56
|
+
#
|
57
|
+
# channel_id - the channel id (number)
|
58
|
+
# drain_id - the drain id (string, given from {create_drain})
|
59
|
+
# url - the url to drain events to, like "syslog://host:port/"
|
60
|
+
def set_drain_url(channel_id, drain_id, url)
|
61
|
+
json_post("/v2/channels/#{channel_id}/drains/#{drain_id}", :url => url)
|
62
|
+
end # def set_drain_url
|
63
|
+
|
64
|
+
# Public: Delete a drain
|
65
|
+
#
|
66
|
+
# channel_id - the channel id (number)
|
67
|
+
# drain_id - the drain id (string, given from {create_drain})
|
68
|
+
def delete_drain(channel_id, drain_id)
|
69
|
+
delete("/v2/channels/#{channel_id}/drains/#{drain_id}")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a event stream session on a channel.
|
73
|
+
#
|
74
|
+
# channel_id - the channel id (number)
|
75
|
+
# server_id - the server id to use in this request
|
76
|
+
#
|
77
|
+
# Note: The 'server_id' is just used for request routing purposes. When
|
78
|
+
# creating and reading a session, you *must* use the same server_id in both
|
79
|
+
# requests. This lets any load balancer in front of logplex pin the session
|
80
|
+
# create and read to the same backend logplex session.
|
81
|
+
def create_session(channel_id, server_id, opts = {})
|
82
|
+
# The 'foo=bar&' part is due to how we use haproxy for pinning
|
83
|
+
# Also channel_id should be a string, also.
|
84
|
+
opts = opts.merge(:channel_id => channel_id.to_s)
|
85
|
+
# num needs to be a string
|
86
|
+
opts[:num] = opts[:num].to_s if opts.has_key?(:num)
|
87
|
+
# If the 'tail' opt is false, remove it.
|
88
|
+
opts.delete(:tail) if !opts[:tail]
|
89
|
+
json_post("/v2/sessions?foo=bar&srv=#{server_id}", opts)
|
90
|
+
end # def create_session
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Private: Do an http GET an expect JSON response.
|
95
|
+
#
|
96
|
+
# Returns the ruby-equivalent object of the JSON data.
|
97
|
+
def json_get(path, options = {})
|
98
|
+
options = { :symbolize_keys => true }.merge(options)
|
99
|
+
options.update(:accept => "application/json")
|
100
|
+
symbolize_keys = options.delete(:symbolize_keys)
|
101
|
+
|
102
|
+
body = get(path, options)
|
103
|
+
MultiJson.load(body, :symbolize_keys => symbolize_keys)
|
104
|
+
end # def json_get
|
105
|
+
|
106
|
+
# Private: Do an http POST an expect JSON response.
|
107
|
+
#
|
108
|
+
# Returns the ruby-equivalent object of the JSON data.
|
109
|
+
def json_post(path, body = {}, options = {})
|
110
|
+
options = { :symbolize_keys => true }.merge(options)
|
111
|
+
options.update(:accept => "application/json")
|
112
|
+
symbolize_keys = options.delete(:symbolize_keys)
|
113
|
+
|
114
|
+
resp = post(path, MultiJson.dump(body), options)
|
115
|
+
MultiJson.load(resp, :symbolize_keys => symbolize_keys)
|
116
|
+
end # def json_post
|
117
|
+
|
118
|
+
# Private: Do an http GET.
|
119
|
+
#
|
120
|
+
# Passes path and options to RestClient without modification.
|
121
|
+
#
|
122
|
+
# Returns the response body.
|
123
|
+
# Raises NotFound on 404
|
124
|
+
# Raises Unauthorized on authentication failure
|
125
|
+
# Raises Error on any other failure (socket error, etc)
|
126
|
+
def get(path, options = {})
|
127
|
+
with_error_translation(path) do
|
128
|
+
connection[path].get(options)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Private: Do an http POST.
|
133
|
+
#
|
134
|
+
# Passes path and options to RestClient without modification.
|
135
|
+
#
|
136
|
+
# Returns the response body.
|
137
|
+
# Raises NotFound on 404
|
138
|
+
# Raises Unauthorized on authentication failure
|
139
|
+
# Raises Error on any other failure (socket error, etc)
|
140
|
+
def post(path, body, options = {})
|
141
|
+
with_error_translation(path) do
|
142
|
+
connection[path].post(body, options)
|
143
|
+
end
|
144
|
+
end # def post
|
145
|
+
|
146
|
+
# Private: Do an http DELETE.
|
147
|
+
#
|
148
|
+
# Passes path and options to RestClient without modification.
|
149
|
+
#
|
150
|
+
# Returns the response body.
|
151
|
+
# Raises NotFound on 404
|
152
|
+
# Raises Unauthorized on authentication failure
|
153
|
+
# Raises Error on any other failure (socket error, etc)
|
154
|
+
def delete(path, options = {})
|
155
|
+
with_error_translation(path) do
|
156
|
+
connection[path].delete(options)
|
157
|
+
end
|
158
|
+
end # def delete
|
159
|
+
|
160
|
+
# Private: Call the block and wrap expected exceptions with the http path.
|
161
|
+
#
|
162
|
+
# Returns the result of the block on success.
|
163
|
+
def with_error_translation(path)
|
164
|
+
yield
|
165
|
+
rescue RestClient::ResourceNotFound => e
|
166
|
+
raise NotFound, "The path `#{path}` could not be found."
|
167
|
+
rescue RestClient::Unauthorized
|
168
|
+
raise Unauthorized, "Logplex authentication failed"
|
169
|
+
rescue RestClient::Exception, SystemCallError, SocketError => e
|
170
|
+
message = e.respond_to?(:http_code) ? e.http_code : "#{e.class}: #{e.message}"
|
171
|
+
message = "(#{message})" if message
|
172
|
+
raise Error, "Trouble communicating with Logplex. Try again soon. #{message}".strip
|
173
|
+
end
|
174
|
+
|
175
|
+
# Private Get an instance of RestClient::Resource to use as the http interface.
|
176
|
+
#
|
177
|
+
# Subsequent calls to this will return the same object instance.
|
178
|
+
#
|
179
|
+
# Returns an instnace of RestClient::Resource
|
180
|
+
def connection
|
181
|
+
@connection ||= RestClient::Resource.new(@url,
|
182
|
+
:verify_ssl => ssl_verification() )
|
183
|
+
end # def connection
|
184
|
+
|
185
|
+
def ssl_verification
|
186
|
+
if ENV['SSL_VERIFY_NONE'] then
|
187
|
+
OpenSSL::SSL::VERIFY_NONE
|
188
|
+
else
|
189
|
+
OpenSSL::SSL::VERIFY_PEER
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end # class Logplex::Client::Backends::HTTP
|