langda 0.1.0 → 0.1.1
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 +4 -4
- data/README.md +1 -1
- data/lib/langda/patches.rb +129 -74
- data/lib/langda/version.rb +1 -1
- data/lib/langda.rb +0 -1
- metadata +1 -2
- data/lib/langda/logger.rb +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 32128642b12f722a798887e1be70fd8820af2b498b4bb29848a27104a8002e9f
|
|
4
|
+
data.tar.gz: de5538f68d89d71fd05bd013afa126863755d11bdcd9d0ce302c5e61c1e01a92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 36899fb283dc7ff1411c25b61c2e8e16abc52252ccd11a9281e5d329bc64ddee19e70239d21ea56a21b600cb97aea63397355a9ac8b0e9a517dce90347752b7f
|
|
7
|
+
data.tar.gz: e485b13e58ced52fe06e13255f8cfe0f069ee0446984f12333af914c752a6155bbdcc76039b112e1c9a7746160caa8acc5c6b5b8f7833f94c5d58e4ce51046f6
|
data/README.md
CHANGED
data/lib/langda/patches.rb
CHANGED
|
@@ -1,105 +1,160 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
module IterationLogger
|
|
6
|
+
VERSION = "0.1.0"
|
|
7
|
+
|
|
8
|
+
ITERATION_METHODS = [
|
|
9
|
+
:each, :map, :collect, :select, :find_all, :reject, :grep, :grep_v,
|
|
10
|
+
:each_with_index, :flat_map, :inject, :reduce, :partition, :find,
|
|
11
|
+
:any?, :all?, :none?, :times
|
|
12
|
+
].to_set.freeze
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def logger
|
|
16
|
+
@logger ||= begin
|
|
17
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
18
|
+
Rails.logger
|
|
19
|
+
else
|
|
20
|
+
std_logger = ::Logger.new($stdout)
|
|
21
|
+
std_logger.level = ::Logger::INFO
|
|
22
|
+
std_logger.progname = "Langda Logger"
|
|
23
|
+
std_logger
|
|
18
24
|
end
|
|
19
|
-
|
|
20
|
-
result = yield(inner)
|
|
21
|
-
|
|
22
|
-
_langda_log(kind, count, start)
|
|
23
|
-
result
|
|
24
|
-
|
|
25
|
-
rescue => e
|
|
26
|
-
Langda::Log.warn("Langda fallback for #{kind}: #{e.class} #{e.message}")
|
|
27
|
-
yield(block) # fallback super
|
|
28
25
|
end
|
|
29
26
|
end
|
|
30
27
|
|
|
28
|
+
# Enable the TracePoint listener (idempotent)
|
|
29
|
+
def enable!
|
|
30
|
+
return if enabled?
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
@tracepoint = TracePoint.new(:call, :c_call) do |tp|
|
|
33
|
+
begin
|
|
34
|
+
handle_tracepoint(tp)
|
|
35
|
+
rescue => e
|
|
36
|
+
# Avoid raising inside TracePoint (would be fatal)
|
|
37
|
+
logger.error("Langda Logger internal error: #{e.class}: #{e.message}\n#{e.backtrace&.first(5)&.join("\n")}")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
@tracepoint.enable
|
|
42
|
+
@enabled = true
|
|
43
|
+
logger.info("Langda Logger enabled (version #{VERSION})")
|
|
38
44
|
end
|
|
39
45
|
|
|
40
|
-
def
|
|
41
|
-
|
|
46
|
+
def disable!
|
|
47
|
+
return unless enabled?
|
|
48
|
+
@tracepoint&.disable
|
|
49
|
+
@tracepoint = nil
|
|
50
|
+
@enabled = false
|
|
51
|
+
logger.info("Langda Logger disabled")
|
|
42
52
|
end
|
|
43
53
|
|
|
44
|
-
def
|
|
45
|
-
|
|
54
|
+
def enabled?
|
|
55
|
+
!!@enabled
|
|
46
56
|
end
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
_safe_loop(:reject, args, block) { |inner| super(*args, &inner) }
|
|
50
|
-
end
|
|
58
|
+
private
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
# Decide whether to log and what to log
|
|
61
|
+
def handle_tracepoint(tp)
|
|
62
|
+
method_sym = tp.method_id
|
|
63
|
+
return unless method_sym && ITERATION_METHODS.include?(method_sym)
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
65
|
+
path = tp.path
|
|
66
|
+
lineno = tp.lineno
|
|
59
67
|
|
|
68
|
+
# We only log when the call site is inside /app/
|
|
69
|
+
return unless path && path.include?("/app/")
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#########################################################
|
|
71
|
+
receiver = safe_receiver(tp)
|
|
72
|
+
class_name = receiver_class_name(receiver, tp)
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
_safe_loop(:times, [], block) { |inner| super(&inner) }
|
|
67
|
-
end
|
|
74
|
+
method_name = method_sym.to_s
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
# Try to determine "current count" - number of elements to be iterated
|
|
77
|
+
count = determine_count(receiver, method_sym)
|
|
78
|
+
|
|
79
|
+
message = {
|
|
80
|
+
file: path,
|
|
81
|
+
line: lineno,
|
|
82
|
+
class: class_name,
|
|
83
|
+
method: method_name,
|
|
84
|
+
count: count
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Use Rails.logger if available, otherwise STDOUT via our logger
|
|
88
|
+
logger.info("Langda Logger: #{message}")
|
|
71
89
|
end
|
|
72
90
|
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
# Safely fetch the receiver (tp.self can sometimes be nil/corrupt in odd cases; rescue)
|
|
92
|
+
def safe_receiver(tp)
|
|
93
|
+
tp.self
|
|
94
|
+
rescue => _
|
|
95
|
+
nil
|
|
75
96
|
end
|
|
76
97
|
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
|
|
98
|
+
def receiver_class_name(receiver, tp)
|
|
99
|
+
if receiver
|
|
100
|
+
# Prefer actual receiver class name
|
|
101
|
+
receiver.class.name rescue tp.defined_class.to_s
|
|
102
|
+
else
|
|
103
|
+
# Fallback to defined_class or '?'
|
|
104
|
+
(tp.defined_class && tp.defined_class.to_s) || "Unknown"
|
|
80
105
|
end
|
|
81
106
|
end
|
|
82
107
|
|
|
108
|
+
# Best-effort to determine count:
|
|
109
|
+
# - For Integer#times, the receiver (an Integer) itself is the count
|
|
110
|
+
# - Prefer length, size, then count method if available, but call in safe rescue
|
|
111
|
+
# - For ActiveRecord::Relation, size may perform DB work; user should be aware
|
|
112
|
+
def determine_count(receiver, method_sym)
|
|
113
|
+
# Integer#times => receiver is an Integer
|
|
114
|
+
if method_sym == :times && receiver.is_a?(Integer)
|
|
115
|
+
return receiver
|
|
116
|
+
end
|
|
83
117
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
118
|
+
return nil unless receiver
|
|
119
|
+
|
|
120
|
+
# Try methods in an order that is best-effort and less likely to cause heavy DB ops
|
|
121
|
+
[:length, :size, :count].each do |m|
|
|
122
|
+
if receiver.respond_to?(m)
|
|
123
|
+
begin
|
|
124
|
+
val = receiver.public_send(m)
|
|
125
|
+
# Ensure it's numeric
|
|
126
|
+
return val if val.is_a?(Integer)
|
|
127
|
+
rescue => _
|
|
128
|
+
# swallow - sometimes ActiveRecord proxies may raise when calling count/size
|
|
129
|
+
next
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
90
133
|
|
|
91
|
-
|
|
134
|
+
nil
|
|
92
135
|
end
|
|
93
|
-
|
|
94
136
|
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
137
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
# Railtie to auto-start in Rails apps
|
|
139
|
+
if defined?(Rails)
|
|
140
|
+
require "rails/railtie"
|
|
141
|
+
|
|
142
|
+
class Railtie < Rails::Railtie
|
|
143
|
+
initializer "iteration_logger.configure_rails_initialization" do
|
|
144
|
+
# Enable after Rails finishes initializing to ensure Rails.logger is available
|
|
145
|
+
ActiveSupport.on_load(:after_initialize) do
|
|
146
|
+
begin
|
|
147
|
+
IterationLogger.enable!
|
|
148
|
+
rescue => e
|
|
149
|
+
IterationLogger.logger.error("Langda Logger failed to enable: #{e.class}: #{e.message}")
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
101
153
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
154
|
+
# Allow config flag to disable if apps wish to
|
|
155
|
+
rake_tasks do
|
|
156
|
+
# no rake tasks; placeholder so Rails doesn't warn about railtie with no hooks
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
data/lib/langda/version.rb
CHANGED
data/lib/langda.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: langda
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- mrmalvi
|
|
@@ -42,7 +42,6 @@ files:
|
|
|
42
42
|
- bin/console
|
|
43
43
|
- bin/setup
|
|
44
44
|
- lib/langda.rb
|
|
45
|
-
- lib/langda/logger.rb
|
|
46
45
|
- lib/langda/patches.rb
|
|
47
46
|
- lib/langda/version.rb
|
|
48
47
|
- sig/langda.rbs
|
data/lib/langda/logger.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module Langda
|
|
2
|
-
module Log
|
|
3
|
-
APP_ROOT = Rails.root.to_s
|
|
4
|
-
def self.warn(msg)
|
|
5
|
-
|
|
6
|
-
loc = caller.find { |c| c.start_with?(APP_ROOT) }
|
|
7
|
-
|
|
8
|
-
loc = caller.find do |c|
|
|
9
|
-
c.include?("#{APP_ROOT}/app/")
|
|
10
|
-
end
|
|
11
|
-
return unless loc
|
|
12
|
-
file = loc.split(":")
|
|
13
|
-
if defined?(Rails) && Rails.logger
|
|
14
|
-
super("[Langda] #{msg} at #{file}")
|
|
15
|
-
else
|
|
16
|
-
puts ("[Langda] #{msg} at #{file}")
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|