Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/common/logger.rb
4085 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
require 'forwardable'
21
require 'logger'
22
23
module Selenium
24
module WebDriver
25
#
26
# @example Enable full logging
27
# Selenium::WebDriver.logger.level = :debug
28
#
29
# @example Log to file
30
# Selenium::WebDriver.logger.output = 'selenium.log'
31
#
32
# @example Use logger manually
33
# Selenium::WebDriver.logger.info('This is info message')
34
# Selenium::WebDriver.logger.warn('This is warning message')
35
#
36
class Logger
37
extend Forwardable
38
39
def_delegators :@logger,
40
:close,
41
:debug?,
42
:info?,
43
:warn?,
44
:error?,
45
:fatal, :fatal?,
46
:level
47
48
#
49
# @param [String] progname Allow child projects to use Selenium's Logger pattern
50
#
51
def initialize(progname = 'Selenium', default_level: nil, ignored: nil, allowed: nil)
52
default_level ||= $DEBUG || ENV.key?('DEBUG') ? :debug : :warn
53
54
@logger = create_logger(progname, level: default_level)
55
@ignored = Array(ignored)
56
@allowed = Array(allowed)
57
@first_warning = false
58
@level_forced = false
59
@output_forced = false
60
end
61
62
#
63
# Forces debug level and prevents it from being overridden.
64
#
65
def debug!
66
@level_forced = true
67
@logger.level = :debug
68
end
69
70
#
71
# Forces output to stderr and prevents it from being overridden.
72
#
73
def stderr!
74
@output_forced = true
75
@logger.reopen($stderr)
76
end
77
78
def level=(level)
79
if @level_forced
80
warn('Logger level is forced; ignoring override', id: :logger)
81
return
82
end
83
84
if level == :info && @logger.level == :info
85
info(':info is now the default log level, to see additional logging, set log level to :debug')
86
end
87
88
@logger.level = level
89
end
90
91
#
92
# Changes logger output to a new IO.
93
#
94
# @param [String] io
95
#
96
def output=(io)
97
if @output_forced
98
warn('Logger output is forced; ignoring override', id: :logger)
99
return
100
end
101
102
@logger.reopen(io)
103
end
104
105
#
106
# Returns IO object used by logger internally.
107
#
108
# Normally, we would have never needed it, but we want to
109
# use it as IO object for all child processes to ensure their
110
# output is redirected there.
111
#
112
# It is only used in debug level, in other cases output is suppressed.
113
#
114
# @api private
115
#
116
def io
117
@logger.instance_variable_get(:@logdev).dev
118
end
119
120
#
121
# Will not log the provided ID.
122
#
123
# @param [Array, Symbol] ids
124
#
125
def ignore(*ids)
126
@ignored += Array(ids).flatten
127
end
128
129
#
130
# Will only log the provided ID.
131
#
132
# @param [Array, Symbol] ids
133
#
134
def allow(*ids)
135
@allowed += Array(ids).flatten
136
end
137
138
#
139
# Used to supply information of interest for debugging a problem
140
# Overrides default #debug to skip ignored messages by provided id
141
#
142
# @param [String] message
143
# @param [Symbol, Array<Symbol>] id
144
# @yield see #deprecate
145
#
146
def debug(message, id: [], &block)
147
discard_or_log(:debug, message, id, &block)
148
end
149
150
#
151
# Used to supply information of general interest
152
#
153
# @param [String] message
154
# @param [Symbol, Array<Symbol>] id
155
# @yield see #deprecate
156
#
157
def info(message, id: [], &block)
158
discard_or_log(:info, message, id, &block)
159
end
160
161
#
162
# Used to supply information that suggests an error occurred
163
#
164
# @param [String] message
165
# @param [Symbol, Array<Symbol>] id
166
# @yield see #deprecate
167
#
168
def error(message, id: [], &block)
169
discard_or_log(:error, message, id, &block)
170
end
171
172
#
173
# Used to supply information that suggests action be taken by user
174
#
175
# @param [String] message
176
# @param [Symbol, Array<Symbol>] id
177
# @yield see #deprecate
178
#
179
def warn(message, id: [], &block)
180
discard_or_log(:warn, message, id, &block)
181
end
182
183
#
184
# Marks code as deprecated with/without replacement.
185
#
186
# @param [String] old
187
# @param [String, nil] new
188
# @param [Symbol, Array<Symbol>] id
189
# @param [String] reference
190
# @yield appends additional message to end of provided template
191
#
192
def deprecate(old, new = nil, id: [], reference: '', &block)
193
id = Array(id)
194
return if @ignored.include?(:deprecations)
195
196
id << :deprecations if @allowed.include?(:deprecations)
197
198
message = "[DEPRECATION] #{old} is deprecated"
199
message << if new
200
". Use #{new} instead."
201
else
202
' and will be removed in a future release.'
203
end
204
message << " See explanation for this deprecation: #{reference}." unless reference.empty?
205
206
discard_or_log(:warn, message, id, &block)
207
end
208
209
private
210
211
def create_logger(name, level:)
212
logger = ::Logger.new($stderr)
213
logger.progname = name
214
logger.level = level
215
logger.formatter = proc do |severity, time, progname, msg|
216
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n".force_encoding('UTF-8')
217
end
218
219
logger
220
end
221
222
def discard_or_log(level, message, id)
223
id = Array(id)
224
return if @ignored.intersect?(id)
225
return if @allowed.any? && !@allowed.intersect?(id)
226
227
return if ::Logger::Severity.const_get(level.upcase) < @logger.level
228
229
unless @first_warning
230
@first_warning = true
231
info("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
232
"https://selenium.dev/documentation/webdriver/troubleshooting/logging\n"
233
end
234
end
235
236
msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
237
msg += " #{yield}" if block_given?
238
239
@logger.send(level) { msg }
240
end
241
end # Logger
242
end # WebDriver
243
end # Selenium
244
245