lib/ffi/libfuse/adapter/debug.rb in ffi-libfuse-0.3.4 vs lib/ffi/libfuse/adapter/debug.rb in ffi-libfuse-0.4.0

- old
+ new

@@ -1,15 +1,26 @@ # frozen_string_literal: true +require_relative 'safe' + module FFI module Libfuse module Adapter # Debug callbacks # # When included in a filesystem class, and if debugging is enabled via {Main#fuse_debug}, then installs a wrapper - # via #{FuseCallbacks#fuse_wrappers} to log callbacks via #warn + # via #{FuseCallbacks#fuse_wrappers} to log callbacks. + # + # Simple format options can be handled by #{debug_config}, or override the **Module Functions** on an including + # class for more programmatic control of output. + # + # @note {Debug} includes {Safe} as it expects to handle (and re-raise) exceptions. module Debug + include Safe + + # Default format + # @see debug_callback DEFAULT_FORMAT = "%<p>s %<n>s %<t>s %<m>s(%<a>s)\n\t=> %<r>s" # @return [Boolean] true if debug is enabled def debug? @debug @@ -24,12 +35,12 @@ # @!visibility private def fuse_wrappers(*wrappers) conf = { prefix: self.class.name }.merge!(debug_config) # validate config for bad formats, strftime etc - Debug.debug_format(:test_debug, [], :result, **conf) - wrappers << proc { |fm, *args, &b| Debug.debug_callback(fm, *args, **conf, &b) } if debug? + debug_format(:test_debug, [], :result, **conf) + wrappers << proc { |fm, *args, &b| debug_callback(fm, *args, **conf, &b) } if debug? return wrappers unless defined?(super) super(*wrappers) end @@ -39,51 +50,78 @@ @debug = enabled end module_function - # Debug fuse method, args and result + # Debug fuse method, args and result of yielding args to the block + # # @param [Symbol] fuse_method the callback name # @param [Array] args callback arguments - # @param [Hash<Symbol,String>] options see {debug} for defaults + # @param [Hash<Symbol,String>] options see {debug_format} for defaults # @option options [String] prefix # @option options [String] strftime a date time format # @option options [String] format format string with fields # # * %<n>: Time.now - use strftime option to control time format # * %<t>: Thread name # * %<m>: Fuse method # * %<a>: Comma separate list of arguments # * %<r>: Result of the method call (or any error raised) # * %<p>: The value of prefix option + # @raise [SystemCallError] + # expected Errors raised from callbacks are logged with their cause (if any) + # @raise [StandardError,ScriptError] + # unexpected Errors raised from callbacks are logged with their backtrace def debug_callback(fuse_method, *args, **options) - debug(fuse_method, args, yield(*args), **options) - rescue SystemCallError => e - # expected behaviour - debug(fuse_method, args, "#{e.class.name}(errno=#{e.errno}): #{e.message}", **options) - raise + result = yield(*args) + debug(fuse_method, args, result, **options) + result rescue StandardError, ScriptError => e - # unexpected, debug with backtrace - debug(fuse_method, args, (["#{e.class.name}: #{e.message}"] + e.backtrace).join("\n\t"), **options) + debug(fuse_method, args, error_message(e), **options) + debug_error(e) raise end - # @!visibility private + # @!group Module Functions + + # Logs the callback def debug(fuse_method, args, result, **options) warn debug_format(fuse_method, args, result, **options) - result end - # @!visibility private + # @param [Exception] err + # @return [String] the detailed error message for err + def error_message(err) + if err.is_a?(SystemCallError) + "#{err.class.name}(errno=#{err.errno}): #{err.message}" + else + "#{err.class.name}: #{err.message}" + end + end + + # Log additional information for errors (cause/backtrace etc) + # @see debug_callback + def debug_error(err) + if err.is_a?(SystemCallError) + warn "Caused by #{error_message(err.cause)}" if err.cause + else + warn err.backtrace.join("\n\t") + end + end + + # @return [String] the formatted debug message + # @see debug_callback def debug_format(fuse_method, args, result, prefix: 'DEBUG', strftime: '%FT%T%:z', format: DEFAULT_FORMAT) format(format, p: prefix, n: Time.now.strftime(strftime), t: Thread.current.name || Thread.current, m: fuse_method, a: args.map(&:to_s).join(','), r: result) end + + # @!endgroup end end end end