custom_log_space 0.1.1 → 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: 86f641a93a9acedc9acd1bd245dc3647a8ff0c03cc51e86a2f460e1d2129eb69
4
- data.tar.gz: 28f2797855109065af34d10c97fb84232d0f5d19982a33bfd8805867c7e2863e
3
+ metadata.gz: 1d0e3ad542c322fac2dae3da5cb1777a9ca18f6e60725e7886bf1bc21df9dce9
4
+ data.tar.gz: 6b97fca2a8072335da8a712fc9884a7b7665a211d811dd51eb2e829126e8e6b6
5
5
  SHA512:
6
- metadata.gz: e61a8eea062c891e6b84e1b221ade929e01e27201f65d420d2909681fb61eac3ea89292a79013da0ac569fda9619af05913459c6961b1ef8591cd0768e695f59
7
- data.tar.gz: 343a26cfd26d3191e371b059985a1056ee0b4a84b2a279ac2c33515255e8e6ab4e1952f29bc84e90c4352fdfa1dd3dd3dbd31785a3e9972094ed87da911a7478
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,9 @@
1
1
  ## [Unreleased]
2
2
 
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
+
3
7
  ## [0.1.1] - 2023-09-13
4
8
  ### Added
5
9
  - Added `cleanup_old_directories` method to manage and delete old directories, ensuring only the two most recent date-directories remain.
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,9 +27,33 @@ $ 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
+ ```
53
+
54
+ ## Retention Policy
29
55
 
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">
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.
31
57
 
32
58
  ## Ignoring Logs in Git
33
59
  If needed, add `/log/custom_log_space/*` to your `.gitignore` to ensure the logs aren't committed to your repository.
@@ -1,130 +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.
6
10
  # https://github.com/rails/rails/blob/7-0-stable/activesupport/lib/active_support/log_subscriber.rb
7
11
  class BaseSubscriber < ActiveSupport::LogSubscriber
12
+ include CustomLogSpace::LogWriter
13
+ include CustomLogSpace::LogFormatter
14
+
8
15
  def start_processing(event)
9
- setup_thread_variables(event.payload)
16
+ ThreadManager.setup(event.payload)
10
17
  end
11
18
 
12
19
  def process_action(event)
13
- payload = event.payload
14
- status = payload[:status]
15
- duration = event.duration.round(2)
16
- view_runtime = payload[:view_runtime]&.round(2)
17
- db_runtime = payload[:db_runtime]&.round(2)
18
- allocations = event.allocations
19
-
20
- message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{duration}ms " \
21
- "(Views: #{view_runtime}ms | ActiveRecord: #{db_runtime}ms | Allocations: #{allocations})"
22
-
20
+ message = format_message(event)
23
21
  log_message(message)
24
- clear_thread_variables
25
- end
26
-
27
- private
28
-
29
- def setup_thread_variables(payload)
30
- Thread.current[:current_controller] = payload[:controller]
31
- Thread.current[:current_action] = payload[:action]
32
- Thread.current[:path] = payload[:path]
33
- Thread.current[:params] = payload[:params].except(:controller, :action)
34
- Thread.current[:header_written] = false
35
- end
36
-
37
- def clear_thread_variables
38
- Thread.current[:current_controller] = nil
39
- Thread.current[:current_action] = nil
40
- Thread.current[:path] = nil
41
- Thread.current[:params] = nil
42
- Thread.current[:header_written] = nil
43
- end
44
-
45
- def log_message(message)
46
- current_controller = Thread.current[:current_controller]
47
- current_action = Thread.current[:current_action]
48
-
49
- return unless current_controller && current_action
50
-
51
- FileUtils.mkdir_p(controller_log_directory) unless Dir.exist?(controller_log_directory)
52
- write_to_custom_log(message)
53
- cleanup_old_directories
54
- end
55
-
56
- def cleanup_old_directories
57
- base_directory = File.join(Rails.root, "log", "custom_log_space")
58
- all_directories = Dir.entries(base_directory).select do |entry|
59
- File.directory?(File.join(base_directory, entry)) && entry !~ /^\./
60
- end.sort
61
-
62
- # If there are more than 2 date-directories, remove the oldest one
63
- while all_directories.size > 2
64
- directory_to_remove = all_directories.shift
65
- path_to_remove = File.join(base_directory, directory_to_remove)
66
- FileUtils.rm_rf(path_to_remove)
67
- end
68
- end
69
-
70
- def custom_log_directory
71
- today = Time.now.strftime("%Y%m%d")
72
- time = Time.now.strftime("%H%M")
73
- File.join(Rails.root, "log", "custom_log_space", today, time)
74
- end
75
-
76
- def controller_log_directory
77
- controller_name = Thread.current[:current_controller].underscore
78
- File.join(custom_log_directory, controller_name)
79
- end
80
-
81
- def custom_log_file_path
82
- action_name = Thread.current[:current_action]
83
- log_file_name = "#{action_name}.log"
84
- File.join(controller_log_directory, log_file_name)
85
- end
86
-
87
- def write_to_custom_log(message)
88
- custom_log_path = custom_log_file_path
89
-
90
- File.open(custom_log_path, "a") do |file|
91
- write_header_information(file)
92
- file.puts(message)
93
- end
94
- rescue SystemCallError, IOError => e
95
- handle_file_error(e)
96
- end
97
-
98
- def handle_file_error(error)
99
- error_prefix = error.is_a?(SystemCallError) ? "Error" : "IO Error"
100
- puts "#{error_prefix}: #{error.message}"
101
- end
102
-
103
- def write_header_information(file)
104
- return if Thread.current[:header_written]
105
-
106
- current_controller = Thread.current[:current_controller]
107
- current_action = Thread.current[:current_action]
108
-
109
- file.puts("") # Add a blank line for better readability.
110
- write_request_info(file)
111
- write_processing_info(file, current_controller, current_action)
112
- write_parameters_info(file)
113
- Thread.current[:header_written] = true
114
- end
115
-
116
- def write_request_info(file)
117
- formatted_time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
118
- file.puts "Started GET \"#{Thread.current[:path]}\" for ::1 at #{formatted_time}"
119
- end
120
-
121
- def write_processing_info(file, current_controller, current_action)
122
- file.puts "Processing by #{current_controller}##{current_action} as HTML"
123
- end
124
-
125
- def write_parameters_info(file)
126
- params = Thread.current[:params] || {}
127
- file.puts "Parameters: #{params.inspect}" unless params.empty?
22
+ ThreadManager.clear
128
23
  end
129
24
  end
130
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.1"
4
+ VERSION = "0.1.2"
5
5
  end
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.1
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-12 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