log_aggregator 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a893c3bac14478e549eaad2cdf0f4d03d1e9423a61562d4fb97a875e8912d664
4
+ data.tar.gz: 155279de2519b3faa6326c142f9abb72e5ee1e834b0e06a722c133a5c407bb91
5
+ SHA512:
6
+ metadata.gz: 0e4dce7af142dd402842a23866deae9c4b9a624204cfcb8f5231a42587c4d50fdfb37b156595effc821853ca317e9ba3d874e205b6077c8d0b019a863f9365cf
7
+ data.tar.gz: 1960454b2cab71075bbd4d63eb872252e2cfa9074b5290b439bf55d5f62f205dd81763835a650990a007c69fd278706d44700e534ff8c14999ef82ee20d9b09d
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # Parser
2
+
3
+ Test app for SP: log files parser.
4
+ Parses a log file and returns information regarding total visits and unique visits count.
5
+
6
+ ## Installation
7
+
8
+ This Parser app uses ruby 2.6.
9
+ Steps to install:
10
+ * git clone https://github.com/natonnelier/ruby_app.git
11
+ * cd ruby_app && bundle install
12
+
13
+ ## Usage
14
+
15
+ ### List pages with most views in descending order:
16
+ ```shell
17
+ rake parse:visits webserver.log #or my-file-path.log
18
+ ```
19
+
20
+ Prints:
21
+ ```
22
+ /about/2 90 visits
23
+ /contact 89 visits
24
+ /index 82 visits
25
+ /about 81 visits
26
+ /help_page/1 80 visits
27
+ /home 78 visits
28
+ ```
29
+
30
+ ### List pages with most unique page views in descending order:
31
+ ```shell
32
+ rake parse:unique webserver.log #or my-file-path.log
33
+ ```
34
+
35
+ Prints:
36
+ ```
37
+ /help_page/1 23 unique views
38
+ /contact 23 unique views
39
+ /home 23 unique views
40
+ /index 23 unique views
41
+ /about/2 22 unique views
42
+ /about 21 unique views
43
+ ```
44
+
45
+ ### To run tests:
46
+ ```shell
47
+ rspec spec
48
+ ```
49
+ or
50
+ ```shell
51
+ bundle exec rspec spec
52
+ ```
53
+ or
54
+ ```shell
55
+ rake spec
56
+ ```
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ Dir["lib/**/*.rb"].each { |f| require_relative(f) }
5
+ Dir["lib/tasks/*.rake"].each { |f| load(f) }
6
+ require "rspec/core/rake_task"
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %w[lint spec]
11
+ rescue LoadError
12
+ # no rspec available
13
+ end
data/lib/parser.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Main module
4
+ module Parser
5
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "exceptions"
4
+ require_relative "reader"
5
+
6
+ module Parser
7
+ class Client
8
+ attr_reader :file, :options, :data
9
+
10
+ def self.parse(file, options = {})
11
+ new(file, options).parse
12
+ end
13
+
14
+ def initialize(file, options = {})
15
+ @file = file
16
+ @options = options
17
+ end
18
+
19
+ def parse
20
+ read_file
21
+ print_data
22
+ end
23
+
24
+ private
25
+
26
+ def read_file
27
+ @data ||= ::Parser::Reader.new(file).call
28
+ rescue InvalidExtensionException, FileNotFoundException => e
29
+ abort e.message
30
+ end
31
+
32
+ def print_data
33
+ ::Parser::Presenter.new(data, options).call
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Abstract exceptions raised from Error
4
+ module Parser
5
+ class Error < StandardError; end
6
+ class FileNotFoundException < StandardError; end
7
+ class InvalidExtensionException < StandardError; end
8
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'base'
3
+
4
+ module Formats
5
+ class Average < Base
6
+ def call
7
+ output_data
8
+ end
9
+
10
+ private
11
+
12
+ def output_data
13
+ sorted_data.each do |path, ips|
14
+ puts "#{path} average #{average(ips)}"
15
+ end
16
+ end
17
+
18
+ def average(ips)
19
+ ips.size.to_f / ips.uniq.size
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formats
4
+ class Base
5
+ attr_reader :data
6
+
7
+ def initialize(data)
8
+ @data = data
9
+ end
10
+
11
+ private
12
+
13
+ def sorted_data
14
+ data.sort_by { |_, ips| -ips.size }
15
+ end
16
+
17
+ def output_data
18
+ sorted_data.each do |path, ips|
19
+ puts "#{path} #{ips.size} #{description}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formats
4
+ class UniqueVisit < Base
5
+ def call
6
+ ips_uniq!
7
+ output_data
8
+ end
9
+
10
+ private
11
+
12
+ def ips_uniq!
13
+ data.each { |_, ips| ips.uniq! }
14
+ end
15
+
16
+ def description
17
+ "unique views"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formats
4
+ class Visit < Base
5
+ def call
6
+ output_data
7
+ end
8
+
9
+ private
10
+
11
+ def description
12
+ "visits"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parser
4
+ class Presenter
5
+ attr_accessor :data, :options
6
+
7
+ def initialize(data, options = {})
8
+ @data = data
9
+ @options = options
10
+ end
11
+
12
+ def call
13
+ output_formatted_data
14
+ end
15
+
16
+ private
17
+
18
+ def format_class
19
+ return Formats::Average if options[:average]
20
+ return Formats::UniqueVisit if options[:unique]
21
+ Formats::Visit
22
+ end
23
+
24
+ def output_formatted_data
25
+ format_class.new(data).call
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parser
4
+ class Reader
5
+ VALID_EXTENSIONS = %w[.log .txt].freeze
6
+
7
+ attr_accessor :file
8
+
9
+ def initialize(file)
10
+ @file = file
11
+ end
12
+
13
+ def call
14
+ validate_presence
15
+ validate_extension
16
+ aggregate
17
+ end
18
+
19
+ private
20
+
21
+ def validate_extension
22
+ unless VALID_EXTENSIONS.include? File.extname(file)
23
+ raise InvalidExtensionException, "File has to be .log or .txt"
24
+ end
25
+ end
26
+
27
+ def validate_presence
28
+ raise FileNotFoundException, "File not found" unless file && File.exist?(file)
29
+ end
30
+
31
+ def file_lines
32
+ @file_lines ||= File.readlines file
33
+ end
34
+
35
+ def aggregate
36
+ data = Hash.new { |h, key| h[key] = [] }
37
+ file_lines.each do |line|
38
+ path, ip = line.split
39
+ data[path] << ip
40
+ end
41
+ data
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :parse do |args|
4
+ options = {}
5
+ file = ARGV[1]
6
+
7
+ task :visits do
8
+ Parser::Client.parse(file)
9
+ end
10
+
11
+ task :unique do
12
+ options[:unique] = true
13
+ Parser::Client.parse(file, options)
14
+ end
15
+
16
+ task :average do
17
+ options[:average] = true
18
+ Parser::Client.parse(file, options)
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: log_aggregator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nicolas Tonnelier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Parse and count requests by endpoints
14
+ email: ''
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - Rakefile
21
+ - lib/parser.rb
22
+ - lib/parser/client.rb
23
+ - lib/parser/exceptions.rb
24
+ - lib/parser/formats/average.rb
25
+ - lib/parser/formats/base.rb
26
+ - lib/parser/formats/unique_visit.rb
27
+ - lib/parser/formats/visit.rb
28
+ - lib/parser/presenter.rb
29
+ - lib/parser/reader.rb
30
+ - lib/tasks/parser.rake
31
+ homepage: https://rubygems.org/gems/log_aggregator
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.0.3
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: Log Parser and Aggregator
54
+ test_files: []