Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/common/logger.rb
1865 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
end
59
60
def level=(level)
61
if level == :info && @logger.level == :info
62
info(':info is now the default log level, to see additional logging, set log level to :debug')
63
end
64
65
@logger.level = level
66
end
67
68
#
69
# Changes logger output to a new IO.
70
#
71
# @param [String] io
72
#
73
def output=(io)
74
@logger.reopen(io)
75
end
76
77
#
78
# Returns IO object used by logger internally.
79
#
80
# Normally, we would have never needed it, but we want to
81
# use it as IO object for all child processes to ensure their
82
# output is redirected there.
83
#
84
# It is only used in debug level, in other cases output is suppressed.
85
#
86
# @api private
87
#
88
def io
89
@logger.instance_variable_get(:@logdev).dev
90
end
91
92
#
93
# Will not log the provided ID.
94
#
95
# @param [Array, Symbol] ids
96
#
97
def ignore(*ids)
98
@ignored += Array(ids).flatten
99
end
100
101
#
102
# Will only log the provided ID.
103
#
104
# @param [Array, Symbol] ids
105
#
106
def allow(*ids)
107
@allowed += Array(ids).flatten
108
end
109
110
#
111
# Used to supply information of interest for debugging a problem
112
# Overrides default #debug to skip ignored messages by provided id
113
#
114
# @param [String] message
115
# @param [Symbol, Array<Symbol>] id
116
# @yield see #deprecate
117
#
118
def debug(message, id: [], &block)
119
discard_or_log(:debug, message, id, &block)
120
end
121
122
#
123
# Used to supply information of general interest
124
#
125
# @param [String] message
126
# @param [Symbol, Array<Symbol>] id
127
# @yield see #deprecate
128
#
129
def info(message, id: [], &block)
130
discard_or_log(:info, message, id, &block)
131
end
132
133
#
134
# Used to supply information that suggests an error occurred
135
#
136
# @param [String] message
137
# @param [Symbol, Array<Symbol>] id
138
# @yield see #deprecate
139
#
140
def error(message, id: [], &block)
141
discard_or_log(:error, message, id, &block)
142
end
143
144
#
145
# Used to supply information that suggests action be taken by user
146
#
147
# @param [String] message
148
# @param [Symbol, Array<Symbol>] id
149
# @yield see #deprecate
150
#
151
def warn(message, id: [], &block)
152
discard_or_log(:warn, message, id, &block)
153
end
154
155
#
156
# Marks code as deprecated with/without replacement.
157
#
158
# @param [String] old
159
# @param [String, nil] new
160
# @param [Symbol, Array<Symbol>] id
161
# @param [String] reference
162
# @yield appends additional message to end of provided template
163
#
164
def deprecate(old, new = nil, id: [], reference: '', &block)
165
id = Array(id)
166
return if @ignored.include?(:deprecations)
167
168
id << :deprecations if @allowed.include?(:deprecations)
169
170
message = "[DEPRECATION] #{old} is deprecated"
171
message << if new
172
". Use #{new} instead."
173
else
174
' and will be removed in a future release.'
175
end
176
message << " See explanation for this deprecation: #{reference}." unless reference.empty?
177
178
discard_or_log(:warn, message, id, &block)
179
end
180
181
private
182
183
def create_logger(name, level:)
184
logger = ::Logger.new($stderr)
185
logger.progname = name
186
logger.level = level
187
logger.formatter = proc do |severity, time, progname, msg|
188
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n".force_encoding('UTF-8')
189
end
190
191
logger
192
end
193
194
def discard_or_log(level, message, id)
195
id = Array(id)
196
return if @ignored.intersect?(id)
197
return if @allowed.any? && !@allowed.intersect?(id)
198
199
return if ::Logger::Severity.const_get(level.upcase) < @logger.level
200
201
unless @first_warning
202
@first_warning = true
203
info("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
204
"https://selenium.dev/documentation/webdriver/troubleshooting/logging\n"
205
end
206
end
207
208
msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
209
msg += " #{yield}" if block_given?
210
211
@logger.send(level) { msg }
212
end
213
end # Logger
214
end # WebDriver
215
end # Selenium
216
217