custom_log_space 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98b901d882ede4d8684e25e13741a5e65eb6f61cbbae5b4e8bb597c15781d23e
4
- data.tar.gz: bf6f8ccf000f73f92d4b94853847d7f04cfb575b6460bbb791702a1f4ed8514d
3
+ metadata.gz: 1d0e3ad542c322fac2dae3da5cb1777a9ca18f6e60725e7886bf1bc21df9dce9
4
+ data.tar.gz: 6b97fca2a8072335da8a712fc9884a7b7665a211d811dd51eb2e829126e8e6b6
5
5
  SHA512:
6
- metadata.gz: dc4463dfe438bf6d25b200177211506c5e34c3011199caf737013083f121ceb0004d633901d3bf859a89037137b99e9bef5907e1ccdc35ee4e096a8b6e9da096
7
- data.tar.gz: 173effc0824a52f8cf383d91c15c027157b03c2c0ffbf46b99368cb0b9a841a05eba2f37131083f61e880bc95ffb5c1fc4b9fa9183f46f1358c08d910ff3d852
6
+ metadata.gz: a7a9bb6be97c059b281c76d58dda57f495125b05aa2cb406d5a1d348ed06b28299a77f4b8e24ce4c98b832745c932caef0fcfb5858a268e9013594e0414004eb
7
+ data.tar.gz: 3311eff79f825be74b425a762ce1cd130c3ba4e20859cf08d46b21d2e5990edc51c1240a50233491c283317b75282e227a9e195ce87a55dc87fbcad245accc2a
data/.rubocop.yml CHANGED
@@ -12,6 +12,9 @@ Style/StringLiteralsInInterpolation:
12
12
  Layout/LineLength:
13
13
  Max: 150
14
14
 
15
+ Metrics/MethodLength:
16
+ Max: 15
17
+
15
18
  Metrics/BlockLength:
16
19
  Exclude:
17
20
  - 'spec/**/*'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2023-09-12
3
+ ## [0.1.2] - 2023-09-15
4
+ ### Changed
5
+ Modified the file path structure for logs. New structure: log/custom_log_space/#{controller_name}/#{action_name}/#{date}/#{time}.log.
6
+
7
+ ## [0.1.1] - 2023-09-13
8
+ ### Added
9
+ - Added `cleanup_old_directories` method to manage and delete old directories, ensuring only the two most recent date-directories remain.
4
10
 
11
+ ## [0.1.0] - 2023-09-12
5
12
  - Initial release
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  The CustomLogSpace gem allows Rails developers to direct Rails logs to files, organized by each controller and action. This organization simplifies debugging and analysis.
4
4
 
5
+ Thanks to this gem, developers are freed from the hassle of constantly starting the rails server to check logs every time an action in a controller is executed.
6
+
5
7
  ## Installation
6
8
 
7
9
  To begin, add the gem to your application's Gemfile:
@@ -25,10 +27,39 @@ $ gem install custom_log_space
25
27
  ```
26
28
 
27
29
  ## Usage
28
- Logs are saved in the `log/custom_log_space/[date]/[time]/[controller_name]/` directory. The filenames follow the pattern: "[action_name].log".
30
+ Logs are saved in the `log/custom_log_space/#{controller_name}/#{action_name}/#{date}/#{time}.log`.
31
+
32
+ ```
33
+ user log % tree
34
+ .
35
+ ├── custom_log_space
36
+ │   └── articles_controller
37
+ │   ├── index
38
+ │   │   ├── 2023-09-14
39
+ │   │   │   ├── 08:45.log
40
+ │   │   │   └── 08:46.log
41
+ │   │   └── 2023-09-15
42
+ │   │   ├── 02:10.log
43
+ │   │   ├── 08:10.log
44
+ │   │   └── 08:11.log
45
+ │   ├── new
46
+ │   │   └── 2023-09-14
47
+ │   │   └── 08:45.log
48
+ │   └── show
49
+ │   └── 2023-09-15
50
+ │   └── 02:10.log
51
+ └── development.log
52
+ ```
29
53
 
30
- <img width="492" alt="スクリーンショット 2023-09-12 8 37 43" src="https://github.com/nishikawa1031/custom_log_space/assets/53680568/95cf44c8-e256-44d0-b0cb-9d6367601985">
54
+ ## Retention Policy
31
55
 
56
+ To prevent excessive disk usage, logs within the `date` directory are retained for only 3 days. Any logs older than this retention period will be automatically deleted, starting with the oldest. Ensure that you archive or backup logs if you need them for longer periods.
57
+
58
+ ## Ignoring Logs in Git
59
+ If needed, add `/log/custom_log_space/*` to your `.gitignore` to ensure the logs aren't committed to your repository.
60
+ ```
61
+ /log/custom_log_space/*
62
+ ```
32
63
 
33
64
  ## Supported environments
34
65
  - Rails 7
@@ -1,114 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "custom_log_space/log_formatter"
4
+ require "custom_log_space/thread_manager"
5
+ require "custom_log_space/log_writer"
6
+
3
7
  module CustomLogSpace
4
8
  # CustomLogSpace::Subscriber is a class for handling custom logging in Rails applications.
5
9
  # It provides methods for processing different types of log events and organizing log messages.
10
+ # https://github.com/rails/rails/blob/7-0-stable/activesupport/lib/active_support/log_subscriber.rb
6
11
  class BaseSubscriber < ActiveSupport::LogSubscriber
12
+ include CustomLogSpace::LogWriter
13
+ include CustomLogSpace::LogFormatter
14
+
7
15
  def start_processing(event)
8
- setup_thread_variables(event.payload)
16
+ ThreadManager.setup(event.payload)
9
17
  end
10
18
 
11
19
  def process_action(event)
12
- payload = event.payload
13
- status = payload[:status]
14
- duration = event.duration.round(2)
15
- view_runtime = payload[:view_runtime]&.round(2)
16
- db_runtime = payload[:db_runtime]&.round(2)
17
- allocations = event.allocations
18
-
19
- message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{duration}ms " \
20
- "(Views: #{view_runtime}ms | ActiveRecord: #{db_runtime}ms | Allocations: #{allocations})"
21
-
20
+ message = format_message(event)
22
21
  log_message(message)
23
- clear_thread_variables
24
- end
25
-
26
- private
27
-
28
- def setup_thread_variables(payload)
29
- Thread.current[:current_controller] = payload[:controller]
30
- Thread.current[:current_action] = payload[:action]
31
- Thread.current[:path] = payload[:path]
32
- Thread.current[:params] = payload[:params].except(:controller, :action)
33
- Thread.current[:header_written] = false
34
- end
35
-
36
- def clear_thread_variables
37
- Thread.current[:current_controller] = nil
38
- Thread.current[:current_action] = nil
39
- Thread.current[:path] = nil
40
- Thread.current[:params] = nil
41
- Thread.current[:header_written] = nil
42
- end
43
-
44
- def log_message(message)
45
- current_controller = Thread.current[:current_controller]
46
- current_action = Thread.current[:current_action]
47
-
48
- return unless current_controller && current_action
49
-
50
- FileUtils.mkdir_p(controller_log_directory) unless Dir.exist?(controller_log_directory)
51
- write_to_custom_log(message)
52
- end
53
-
54
- def custom_log_directory
55
- today = Time.now.strftime("%Y%m%d")
56
- time = Time.now.strftime("%H%M")
57
- File.join(Rails.root, "log", "custom_log_space", today, time)
58
- end
59
-
60
- def controller_log_directory
61
- controller_name = Thread.current[:current_controller].underscore
62
- File.join(custom_log_directory, controller_name)
63
- end
64
-
65
- def custom_log_file_path
66
- action_name = Thread.current[:current_action]
67
- log_file_name = "#{action_name}.log"
68
- File.join(controller_log_directory, log_file_name)
69
- end
70
-
71
- def write_to_custom_log(message)
72
- custom_log_path = custom_log_file_path
73
-
74
- File.open(custom_log_path, "a") do |file|
75
- write_header_information(file)
76
- file.puts(message)
77
- end
78
- rescue SystemCallError, IOError => e
79
- handle_file_error(e)
80
- end
81
-
82
- def handle_file_error(error)
83
- error_prefix = error.is_a?(SystemCallError) ? "Error" : "IO Error"
84
- puts "#{error_prefix}: #{error.message}"
85
- end
86
-
87
- def write_header_information(file)
88
- return if Thread.current[:header_written]
89
-
90
- current_controller = Thread.current[:current_controller]
91
- current_action = Thread.current[:current_action]
92
-
93
- file.puts("") # Add a blank line for better readability.
94
- write_request_info(file)
95
- write_processing_info(file, current_controller, current_action)
96
- write_parameters_info(file)
97
- Thread.current[:header_written] = true
98
- end
99
-
100
- def write_request_info(file)
101
- formatted_time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
102
- file.puts "Started GET \"#{Thread.current[:path]}\" for ::1 at #{formatted_time}"
103
- end
104
-
105
- def write_processing_info(file, current_controller, current_action)
106
- file.puts "Processing by #{current_controller}##{current_action} as HTML"
107
- end
108
-
109
- def write_parameters_info(file)
110
- params = Thread.current[:params] || {}
111
- file.puts "Parameters: #{params.inspect}" unless params.empty?
22
+ ThreadManager.clear
112
23
  end
113
24
  end
114
25
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CustomLogSpace
4
+ # The LogFormatter module is responsible for formatting log messages.
5
+ module LogFormatter
6
+ private
7
+
8
+ def format_message(event)
9
+ payload = event.payload
10
+ status = payload[:status]
11
+ duration = event.duration.round(2)
12
+ view_runtime = payload[:view_runtime]&.round(2)
13
+ db_runtime = payload[:db_runtime]&.round(2)
14
+ allocations = event.allocations
15
+
16
+ "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{duration}ms " \
17
+ "(Views: #{view_runtime}ms | ActiveRecord: #{db_runtime}ms | Allocations: #{allocations})"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CustomLogSpace
4
+ # The LogWriter module provides methods for writing log messages to custom log files.
5
+ # It allows the creation of log directories, handling file errors, and appending messages to log files.
6
+ module LogWriter
7
+ private
8
+
9
+ def log_message(message)
10
+ current_controller = Thread.current[:current_controller]
11
+ current_action = Thread.current[:current_action]
12
+
13
+ return unless current_controller && current_action
14
+
15
+ write_to_custom_log(message) do |file|
16
+ write_header_information(file)
17
+ end
18
+
19
+ cleanup_old_directories
20
+ end
21
+
22
+ def cleanup_old_directories
23
+ return unless Dir.exist?(action_directory)
24
+
25
+ # If there are more than 3 date-directories, remove the oldest ones
26
+ remove_oldest_directory while all_directories.size > 3
27
+ end
28
+
29
+ def all_directories
30
+ @all_directories ||= Dir.entries(action_directory).select do |entry|
31
+ File.directory?(File.join(action_directory, entry)) && entry !~ /^\./
32
+ end.sort
33
+ end
34
+
35
+ def remove_oldest_directory
36
+ directory_to_remove = all_directories.shift
37
+ path_to_remove = File.join(action_directory, directory_to_remove)
38
+ FileUtils.rm_rf(path_to_remove)
39
+ end
40
+
41
+ def action_directory
42
+ @action_directory ||= begin
43
+ controller_name = Thread.current[:current_controller].underscore
44
+ action_name = Thread.current[:current_action]
45
+ File.join(Rails.root, "log", "custom_log_space", controller_name, action_name)
46
+ end
47
+ end
48
+
49
+ def write_to_custom_log(message)
50
+ directory_path = log_directory_based_on_format
51
+ FileUtils.mkdir_p(directory_path) unless Dir.exist?(directory_path)
52
+ custom_log_path = custom_log_file_path(directory_path)
53
+
54
+ File.open(custom_log_path, "a") do |file|
55
+ yield(file) # Header or other info can be passed and written here
56
+ file.puts(message)
57
+ end
58
+ rescue SystemCallError, IOError => e
59
+ handle_file_error(e)
60
+ end
61
+
62
+ def handle_file_error(error)
63
+ error_prefix = error.is_a?(SystemCallError) ? "Error" : "IO Error"
64
+ puts "#{error_prefix}: #{error.message}"
65
+ end
66
+
67
+ def write_header_information(file)
68
+ return if Thread.current[:header_written]
69
+
70
+ current_controller = Thread.current[:current_controller]
71
+ current_action = Thread.current[:current_action]
72
+
73
+ file.puts("") # Add a blank line for better readability.
74
+ write_request_info(file)
75
+ write_processing_info(file, current_controller, current_action)
76
+ write_parameters_info(file)
77
+ Thread.current[:header_written] = true
78
+ end
79
+
80
+ def write_request_info(file)
81
+ formatted_time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
82
+ file.puts "Started GET \"#{Thread.current[:path]}\" for ::1 at #{formatted_time}"
83
+ end
84
+
85
+ def write_processing_info(file, current_controller, current_action)
86
+ file.puts "Processing by #{current_controller}##{current_action} as HTML"
87
+ end
88
+
89
+ def write_parameters_info(file)
90
+ params = Thread.current[:params] || {}
91
+ file.puts "Parameters: #{params.inspect}" unless params.empty?
92
+ end
93
+
94
+ def custom_log_file_path(directory_path)
95
+ time = Time.now.strftime("%H:%M")
96
+ "#{directory_path}/#{time}.log"
97
+ end
98
+
99
+ def log_directory_based_on_format
100
+ controller_name = Thread.current[:current_controller].underscore
101
+ action_name = Thread.current[:current_action]
102
+ date = Time.now.strftime("%Y-%m-%d")
103
+
104
+ File.join(Rails.root, "log", "custom_log_space", controller_name, action_name, date)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CustomLogSpace
4
+ # The ThreadManager class provides methods for managing thread-local variables related to logging in a Rails application.
5
+ # It is responsible for setting up and clearing thread-local variables such as controller, action, path, params, and header_written.
6
+ class ThreadManager
7
+ # https://railsguides.jp/v6.1/active_support_instrumentation.html#start-processing-action-controller
8
+ # Sets up thread-local variables based on the provided payload.
9
+ #
10
+ # @param payload [Hash] The payload containing information about the current request.
11
+ #
12
+ # Example:
13
+ #
14
+ # payload = {
15
+ # controller: 'HomeController',
16
+ # action: 'index',
17
+ # path: '/home',
18
+ # params: { id: 1, page: 2 }
19
+ # }
20
+ #
21
+ # CustomLogSpace::ThreadManager.setup(payload)
22
+ #
23
+ def self.setup(payload)
24
+ Thread.current[:current_controller] = payload[:controller]
25
+ Thread.current[:current_action] = payload[:action]
26
+ Thread.current[:path] = payload[:path]
27
+ Thread.current[:params] = payload[:params].except(:controller, :action)
28
+ Thread.current[:header_written] = false
29
+ end
30
+
31
+ def self.clear
32
+ Thread.current[:current_controller] = nil
33
+ Thread.current[:current_action] = nil
34
+ Thread.current[:path] = nil
35
+ Thread.current[:params] = nil
36
+ Thread.current[:header_written] = nil
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CustomLogSpace
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  # ViewSubscriber logs view rendering events for CustomLogSpace.
4
4
  # It tracks events like template rendering, partial rendering, and collection rendering.
5
+ # https://github.com/rails/rails/blob/7-0-stable/actionview/lib/action_view/log_subscriber.rb
5
6
  class ViewSubscriber < CustomLogSpace::BaseSubscriber
6
7
  def render_template(event)
7
8
  identifier = event.payload[:identifier]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: custom_log_space
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - nishikawa1031
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-11 00:00:00.000000000 Z
11
+ date: 2023-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -48,10 +48,12 @@ files:
48
48
  - custom_log_space.gemspec
49
49
  - lib/custom_log_space.rb
50
50
  - lib/custom_log_space/base_subscriber.rb
51
+ - lib/custom_log_space/log_formatter.rb
52
+ - lib/custom_log_space/log_writer.rb
51
53
  - lib/custom_log_space/sql_subscriber.rb
54
+ - lib/custom_log_space/thread_manager.rb
52
55
  - lib/custom_log_space/version.rb
53
56
  - lib/custom_log_space/view_subscriber.rb
54
- - sig/change_rails_log_path.rbs
55
57
  - sig/custom_log_space.rbs
56
58
  homepage: https://github.com/nishikawa1031/custom_log_space.git
57
59
  licenses:
@@ -1,4 +0,0 @@
1
- module CustomLogSpace
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end