loggie 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7f44eb361050e8b8c4146d150a7d06154d50ba4
4
+ data.tar.gz: 79640e4eddf1f7509f3318175d146b5be8181665
5
+ SHA512:
6
+ metadata.gz: b2c2b6ed794cbc2d75d2febc1a71fe70a0c4f2687100e2031f58731e4cab9408c296b00bd9a302dc5b277da9a78e5eeee3696d65a9e15f02fa3a8b3c3a1673c8
7
+ data.tar.gz: cfea02fe7b240be9dba042ef639cde88cc4f89b8929c158e94b8451a692fcb8f627463d82bf4319c90bbe17dadd886f2e0d5914a42f0bdaedf1144b879b208f4
data/.env.example ADDED
@@ -0,0 +1,13 @@
1
+ # from https://logentries.com/app/<app>#/user-account/apikey
2
+ READ_TOKEN=key
3
+
4
+ # A comma separated list of log file ids
5
+ LOG_FILES=e20bd6af, c83c7cd7, 6fb426fd, 776dfea9
6
+
7
+ # Depending on the size of the underlying dataset of the complexity of the query,
8
+ # a request may not yield a value straight away. In this case this gem will request
9
+ # the results up until this retry count
10
+ MAX_RETRY=50
11
+
12
+ # Internal logging level. default: info
13
+ LOG_LEVEL=info
data/.env.test ADDED
@@ -0,0 +1,12 @@
1
+ READ_TOKEN=bf3b4d32
2
+
3
+ # A comma separated list of log file ids
4
+ LOG_FILES=e20bd6af,c83c7cd7,6fb426fd,776dfea9
5
+
6
+ # Depending on the size of the underlying dataset of the complexity of the query,
7
+ # a request may not yield a value straight away. In this case this gem will request
8
+ # the results up until this retry count
9
+ MAX_RETRY=50
10
+
11
+ # LOG_LEVEL=info
12
+ LOG_LEVEL=debug
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .env
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.3
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.0
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in loggie.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ian Vaughan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Loggie
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'loggie'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install loggie
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ Loggie.search(query: "foobar")
23
+ => {:timestamp=>Sun, 08 Jan 2017 01:00:58 +0000,
24
+ :message=>
25
+ { "remote_addr"=>"11.11.36.72",
26
+ "version"=>"HTTP/1.1",
27
+ "host"=>"host.com",
28
+ "x_forwared_for"=>"11.11.11.11",
29
+ ...
30
+
31
+ ```
32
+
33
+ Or, use from the command line with:
34
+
35
+ `loggie foobar`
36
+
37
+ ## Development
38
+
39
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
40
+
41
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
42
+
43
+ ## Contributing
44
+
45
+ Bug reports and pull requests are welcome on GitHub at https://github.com/IanVaughan/loggie.
46
+
47
+ 1. Fork it ( https://github.com/IanVaughan/loggie/fork )
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create a new Pull Request
52
+
53
+ ## License
54
+
55
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "loggie"
5
+
6
+ require 'dotenv'
7
+ Dotenv.load
8
+
9
+ require "pry"
10
+ Pry.start
data/bin/loggie ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # Enables search from the console
3
+
4
+ require "bundler/setup"
5
+
6
+ require 'dotenv'
7
+ Dotenv.load
8
+
9
+ require 'loggie'
10
+ puts Loggie.search query: ARGV[0]
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/loggie.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'active_support/all'
2
+ Time.zone = 'Europe/London'
3
+
4
+ require "loggie/version"
5
+ require "loggie/logging"
6
+
7
+ require "loggie/extract"
8
+ require "loggie/request"
9
+
10
+ require "loggie/logentries/search"
11
+ require "loggie/logentries/retry"
12
+ require "loggie/logentries/response"
13
+
14
+ module Loggie
15
+ def self.search(query:, from: 1.week.ago, to: Time.zone.now)
16
+ Logentries::Search.new(query: query, from: from, to: to).call
17
+ end
18
+ end
@@ -0,0 +1,94 @@
1
+ module Loggie
2
+ class Extract
3
+ # Extracts the payload from the response into a more manageable hash.
4
+ # 1. Converts the JSON into a Hash
5
+ # 2. Strips any empty
6
+ # 3. Updates the timestamp from unix to DateTime
7
+ # 4. Removes fields that are not interesting
8
+ # The full log can contain many fields, most are not that great, so are excluded by default
9
+ #
10
+ # Full response hash includes :
11
+ # "remote_addr"=>"11.11.11.161",
12
+ # "request_method"=>"GET",
13
+ # "path_info"=>"/foo/user",
14
+ # "query_string"=>"device_id=00000000-0000-0000-0000-000000000000",
15
+ # "version"=>"HTTP/1.1",
16
+ # "host"=>"server.com",
17
+ # "origin"=>nil,
18
+ # "connection"=>nil,
19
+ # "proxy_connection"=>nil,
20
+ # "referer"=>nil,
21
+ # "x_forwared_for"=>"11.111.232.161",
22
+ # "x_forwared_proto"=>"https",
23
+ # "x_forwared_port"=>"443",
24
+ # "accept"=>"*/*",
25
+ # "accept_encoding"=>"gzip, deflate",
26
+ # "accept_language"=>"en-gb",
27
+ # "content_length"=>nil,
28
+ # "content_type"=>nil,
29
+ # "agent"=>"version",
30
+ # "user_agent"=>"app",
31
+ # "authorization"=>"bearer token",
32
+ # "api_version"=>"20161115",
33
+ # "response_status"=>200,
34
+ # "response_header"=>{"Content-Type"=>"application/json", "Content-Length"=>"819"},
35
+ # "response_body" ....
36
+ # "request_params" ....
37
+ # "duration"
38
+
39
+ DEFAULT_FIELDS_INCLUDED = [
40
+ "request_method", "path_info", "query_string", "agent", "authorization", "response_body", "request_params"
41
+ ]
42
+
43
+ def initialize
44
+ @keep_fields = DEFAULT_FIELDS_INCLUDED
45
+ end
46
+
47
+ ##
48
+ # @param [Array] results hash from the request
49
+ def call(results)
50
+ return if results.nil?
51
+
52
+ results.map do |result|
53
+ formatted_message = format(result["message"])
54
+ next if formatted_message.empty?
55
+
56
+ {
57
+ timestamp: formatted_date(result["timestamp"]),
58
+ message: formatted_message
59
+ }
60
+ end.compact
61
+ end
62
+
63
+ private
64
+
65
+ attr_reader :keep_fields
66
+
67
+ def formatted_date(timestamp)
68
+ Time.at(timestamp / 1000).to_datetime
69
+ end
70
+
71
+ def format(m)
72
+ m = remove_rails_timestamp(m)
73
+ m = safe_parse(m)
74
+ m = remove_empty_fields(m)
75
+ m.except(*keep_fields)
76
+ end
77
+
78
+ def remove_rails_timestamp(message)
79
+ message.sub(/.*-- : /, '')
80
+ end
81
+
82
+ def safe_parse(message, save: true)
83
+ begin
84
+ JSON.parse message
85
+ rescue JSON::ParserError
86
+ {}
87
+ end
88
+ end
89
+
90
+ def remove_empty_fields(m)
91
+ m.compact.reject { |m| m.empty? }
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,31 @@
1
+ module Loggie
2
+ module Logentries
3
+ class Response
4
+ attr_reader :logs, :progress, :links, :id, :leql, :events
5
+
6
+ def initialize(response)
7
+ data = JSON.parse response.read_body
8
+
9
+ @logs = data["logs"]
10
+ @links = data["links"]
11
+ @leql = data["leql"]
12
+
13
+ if data.key?("events") # 200
14
+ @events = data["events"]
15
+ else # 202 for a query that successfully started but has not yet finished
16
+ @progress = data["progress"]
17
+ @id = data["id"]
18
+ end
19
+ end
20
+
21
+ def next_url
22
+ # res.fetch("links", [{}]).first.dig("href").gsub(/\?$/, '')
23
+ links.first["href"]
24
+ end
25
+
26
+ def events?
27
+ !@events.nil?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ module Loggie
2
+ module Logentries
3
+ # Allows a block to be retried a number of times up until MAX_RETRY
4
+ # Each retry will sleep RETRY_DELAY_SECONDS before requesting
5
+ # It checks the response and extracts the polling URI for progress
6
+ class Retry
7
+ include Logging
8
+ MAX_RETRY = ENV.fetch('MAX_RETRY', 5).to_i
9
+ RETRY_DELAY_SECONDS = ENV.fetch('RETRY_DELAY_SECONDS', 0.2).to_f
10
+ MAX_RETRY_DELEY_SECONDS = 20 # max 20 seconds, or it will expire
11
+
12
+ def call(url, method, options, &block)
13
+ # TODO: ensure retry_count is reset or if that matters
14
+ @retry_count ||= 0
15
+ response = block.call(url, method, options)
16
+ logger.debug "#{self.class} retry:#{@retry_count}, response:#{response.body}"
17
+
18
+ if response.code.to_i > 203
19
+ log_and_raise "Failed request with:#{response.message}"
20
+ end
21
+
22
+ res = Response.new response
23
+ return res.events if res.events?
24
+ logger.info "Logentries returned progress:#{res.progress}"
25
+
26
+ @retry_count += 1
27
+ if @retry_count > MAX_RETRY
28
+ log_and_raise "Retry count of #{MAX_RETRY} reached"
29
+ end
30
+
31
+ sleep RETRY_DELAY_SECONDS
32
+
33
+ self.call(res.next_url, :get, nil, &block)
34
+ end
35
+
36
+ private
37
+
38
+ def log_and_raise(message)
39
+ logger.error message
40
+ raise message
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ module Loggie
2
+ module Logentries
3
+ # Main entry point to query a specific log source
4
+ class Search
5
+ include Logging
6
+ BASE_URI = "https://rest.logentries.com"
7
+ QUERY_PATH = "query/logs"
8
+ LOG_FILES = ENV['LOG_FILES']
9
+
10
+ ##
11
+ # @param [String] query: to perform
12
+ # @param [DateTime] from: query from date
13
+ # @param [DateTime] to: query to date
14
+ # @param [Array] log_files: list of log id files to search. default ENV['LOG_FILES']
15
+ #
16
+ def initialize(query: nil, from: nil, to: nil, log_files: nil)
17
+ @query, @from, @to = query, from, to
18
+ @log_files = log_files || log_files_from_env
19
+ @extract = Extract.new
20
+ @request = Request.new(retry_mechanism: Retry.new)
21
+ end
22
+
23
+ def call(query: nil, from: nil, to: nil, log_files: nil)
24
+ options = parsed_post_params(query || @query, from || @from, to || @to, log_files || @log_files)
25
+ logger.debug "#{self.class} options:#{options}, url:#{url}"
26
+
27
+ extract.call(request.call(url, method: :post, options: options))
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :extract, :request
33
+
34
+ def url
35
+ [BASE_URI, QUERY_PATH].join('/')
36
+ end
37
+
38
+ # https://docs.logentries.com/docs/post-query
39
+ def parsed_post_params(query, from, to, log_keys)
40
+ {
41
+ logs: log_keys,
42
+ leql: {
43
+ during: {
44
+ from: convert(from),
45
+ to: convert(to)
46
+ },
47
+ statement: "where(#{query})"
48
+ }
49
+ }
50
+ end
51
+
52
+ def convert(time)
53
+ (time.to_f * 1000).floor
54
+ end
55
+
56
+ def log_files_from_env
57
+ LOG_FILES&.split(",")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+
3
+ module Logging
4
+ LOG_LEVEL = ENV.fetch('LOG_LEVEL', :warn).to_sym
5
+
6
+ class << self
7
+ def logger
8
+ @logger ||= ::Logger.new(STDOUT).tap { |l| l.level = LOG_LEVEL }
9
+ end
10
+
11
+ def logger=(logger)
12
+ @logger = logger
13
+ end
14
+ end
15
+
16
+ def self.included(base)
17
+ class << base
18
+ def logger
19
+ Logging.logger
20
+ end
21
+ end
22
+ end
23
+
24
+ def logger
25
+ Logging.logger
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module Loggie
5
+ # Makes external HTTP request, with a retry mechanism for
6
+ # polling long running queries on remote server
7
+ class Request
8
+ include Logging
9
+ READ_TOKEN = ENV['READ_TOKEN']
10
+
11
+ def initialize(retry_mechanism: )
12
+ @retry_mechanism = retry_mechanism || Retry.new
13
+ end
14
+
15
+ def call(url, method: :get, options: nil)
16
+ retry_mechanism.call(url, method, options) do |url, method, options|
17
+ request(url, method: method, options: options)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :retry_mechanism
24
+
25
+ def request(url, method:, options: nil)
26
+ encoded_options = URI.encode_www_form(options) if options
27
+
28
+ url = if method == :get
29
+ URI([url, encoded_options].compact.join("?"))
30
+ else
31
+ URI(url)
32
+ end
33
+
34
+ http = Net::HTTP.new(url.host, url.port)
35
+ http.use_ssl = true
36
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
37
+
38
+ request = if method == :get
39
+ Net::HTTP::Get.new(url)
40
+ else
41
+ Net::HTTP::Post.new(url)
42
+ end
43
+ request["x-api-key"] = READ_TOKEN
44
+
45
+ if method == :post
46
+ request["content-type"] = 'application/json'
47
+ request.body = options.to_json
48
+ end
49
+
50
+ http.request(request)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Loggie
2
+ VERSION = "0.0.2"
3
+ end
data/loggie.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'loggie/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "loggie"
8
+ spec.version = Loggie::VERSION
9
+ spec.authors = ["Ian Vaughan"]
10
+ spec.email = ["github@ianvaughan.co.uk"]
11
+
12
+ spec.summary = %q{Enables search of log files}
13
+ spec.description = %q{Searches remote log files via API}
14
+ spec.homepage = "https://github.com/IanVaughan/loggie"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables << "loggie"
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "dotenv", "~> 2.1"
22
+ spec.add_dependency "activesupport", "~> 5.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.12"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "pry", "~> 0.10"
28
+ spec.add_development_dependency "timecop", "~> 0.7"
29
+ spec.add_development_dependency "vcr", "~> 2.9"
30
+ spec.add_development_dependency "webmock", "~> 1.22"
31
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loggie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Ian Vaughan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dotenv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.7'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.7'
111
+ - !ruby/object:Gem::Dependency
112
+ name: vcr
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.9'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.9'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.22'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.22'
139
+ description: Searches remote log files via API
140
+ email:
141
+ - github@ianvaughan.co.uk
142
+ executables:
143
+ - loggie
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".env.example"
148
+ - ".env.test"
149
+ - ".gitignore"
150
+ - ".rspec"
151
+ - ".ruby-version"
152
+ - ".travis.yml"
153
+ - Gemfile
154
+ - LICENSE.txt
155
+ - README.md
156
+ - Rakefile
157
+ - bin/console
158
+ - bin/loggie
159
+ - bin/setup
160
+ - lib/loggie.rb
161
+ - lib/loggie/extract.rb
162
+ - lib/loggie/logentries/response.rb
163
+ - lib/loggie/logentries/retry.rb
164
+ - lib/loggie/logentries/search.rb
165
+ - lib/loggie/logging.rb
166
+ - lib/loggie/request.rb
167
+ - lib/loggie/version.rb
168
+ - loggie.gemspec
169
+ homepage: https://github.com/IanVaughan/loggie
170
+ licenses:
171
+ - MIT
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.5.2
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: Enables search of log files
193
+ test_files: []
194
+ has_rdoc: