files.com 1.1.783 → 1.1.784

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7dc95932e61df91c8b29ba13bab73b9e81c4e272d999cad352a79b9af5880e8b
4
- data.tar.gz: 5a84da44b445097b6e4741cd3e969cc8eabbc281d75188908a1c3fcb7443b789
3
+ metadata.gz: cd5e31f4e4c09fa7272e5c337ddc01c434546c93f177fe8fecd887839326f060
4
+ data.tar.gz: 143a0c464a2530296c1e67243d5f8d2e3640cff840c897ae2067517147af45b7
5
5
  SHA512:
6
- metadata.gz: e0da3ee8e594c0049fd065e1d5300d5d71d67000af4acb8a10ef8409fce08874ab785c69b0f57692f512bb3b3e1b37fec0e5c5aed44e3fcbdf84410d5ed0398b
7
- data.tar.gz: 82a14f3125a5317085b9261de7e4baf35dd1459921fd2c436855fc1f34f50fc1774fb4ea46576775d948e0e460b5c278949a6eea90fabd773fa4afffa1757f30
6
+ metadata.gz: 0d5eca777f0554ded3ad22b322bd8dcf959885c986c461a1d478c8097ffb00e2ee6d6741fd426cd36d0031796890f7d6ec7d0400f8c37072ae9079484a856fc7
7
+ data.tar.gz: f377e72e2cdb7e3f49391059d4c4c6115e506053cf7c371e6a0c2957018e701e8f3fd09ef8daeb099c498de22d8ce490826ea66cf596511bc43f8dd3f1fbaa89
data/_VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.783
1
+ 1.1.784
@@ -8,8 +8,29 @@ module Files
8
8
  QUERY_METHODS = %i[get head delete].freeze
9
9
  private_constant :QUERY_METHODS
10
10
 
11
- def initialize(conn = nil)
11
+ # The default for a logging option this client does not set itself.
12
+ USE_GLOBAL = Object.new.freeze
13
+ private_constant :USE_GLOBAL
14
+
15
+ # Creates a client that sends requests through +conn+, or through a new default connection when +conn+ is nil.
16
+ #
17
+ # By default the client logs its ordinary API requests, responses and errors through the library-wide Files.logger and
18
+ # Files.log_level, read as each message is logged. Pass either option to give this client its own setting
19
+ # instead, without changing the library-wide one or any other client:
20
+ #
21
+ # logger:: A Logger, or any object with the same +log+ method, that receives this client's ordinary API messages. Its own
22
+ # level decides which are written, and the client never changes it. Pass nil for no logger even when
23
+ # Files.logger is set.
24
+ # log_level:: Without a logger, the lowest level written to standard output and error: nil, Files::LEVEL_DEBUG,
25
+ # Files::LEVEL_INFO or Files::LEVEL_ERROR, or "debug" or "info", as Files.log_level= accepts. It
26
+ # is ignored when the client has a logger. Pass nil to write nothing there even when
27
+ # Files.log_level is set.
28
+ #
29
+ # A client created with logger: nil, log_level: nil logs no ordinary API messages.
30
+ def initialize(conn = nil, logger: USE_GLOBAL, log_level: USE_GLOBAL)
12
31
  self.conn = conn || self.class.default_conn
32
+ @logger = logger
33
+ @log_level = log_level.equal?(USE_GLOBAL) ? log_level : Util.normalize_log_level(log_level)
13
34
  @system_profiler = SystemProfiler.new
14
35
  @last_request_metrics = nil
15
36
  end
@@ -375,7 +396,7 @@ module Files
375
396
  else
376
397
  "The Files.com API returned an error without a message (HTTP response code was #{resp.http_status})"
377
398
  end
378
- Util.log_error("API error", status: resp.http_status, error_message: message)
399
+ Util.log_error("API error", { status: resp.http_status, error_message: message }, log_settings)
379
400
 
380
401
  api_error_class(resp.data[:type]).new(message,
381
402
  http_body: resp.http_body,
@@ -462,7 +483,7 @@ module Files
462
483
  error.message.empty? ? error.response[:body] : error.message
463
484
  end
464
485
 
465
- Util.log_error("Network error", error_message: error_message)
486
+ Util.log_error("Network error", { error_message: error_message }, log_settings)
466
487
  message = "Could not connect to Files.com at URL #{base_url}. Please check your internet connection and try again. If this problem persists, you should check Files.com's service status at https://status.files.com, or contact your primary account representative."
467
488
  message += " Request was retried #{num_retries} times." if num_retries > 0
468
489
  message += "\n\n(Network error: #{error_message})"
@@ -508,18 +529,25 @@ module Files
508
529
  end
509
530
 
510
531
  private def log_request(context, num_retries, no_body: false)
511
- Util.log_info("Request", method: context.method, num_retries: num_retries, path: context.path)
512
- Util.log_debug("Request details", body: context.body, query_params: context.query_params) unless no_body
532
+ Util.log_info("Request", { method: context.method, num_retries: num_retries, path: context.path }, log_settings)
533
+ Util.log_debug("Request details", { body: context.body, query_params: context.query_params }, log_settings) unless no_body
513
534
  end
514
535
 
515
536
  private def log_response(context, request_start, status, body, no_body: false)
516
- Util.log_info("Response", elapsed: Time.now - request_start, method: context.method, path: context.path, status: status)
517
- Util.log_debug("Response details", body: body) unless no_body
537
+ Util.log_info("Response", { elapsed: Time.now - request_start, method: context.method, path: context.path, status: status }, log_settings)
538
+ Util.log_debug("Response details", { body: body }, log_settings) unless no_body
518
539
  end
519
540
 
520
541
  private def log_response_error(context, request_start, error)
521
- Util.log_error("Error", elapsed: Time.now - request_start, error_type: error.class, method: context.method, path: context.path)
522
- Util.log_debug("Error details", error_message: error.message)
542
+ Util.log_error("Error", { elapsed: Time.now - request_start, error_type: error.class, method: context.method, path: context.path }, log_settings)
543
+ Util.log_debug("Error details", { error_message: error.message }, log_settings)
544
+ end
545
+
546
+ # This client's own logger and level where it set them, and the library-wide ones otherwise.
547
+ private def log_settings
548
+ Util::LogSettings.new(@logger.equal?(USE_GLOBAL) ? Files.logger : @logger,
549
+ @log_level.equal?(USE_GLOBAL) ? Files.log_level : @log_level
550
+ )
523
551
  end
524
552
 
525
553
  class RequestLogContext
@@ -34,29 +34,48 @@ module Files
34
34
  end
35
35
  end
36
36
 
37
- def self.log_error(message, data = {})
38
- if !Files.logger.nil? ||
39
- (!Files.log_level.nil? && Files.log_level <= Files::LEVEL_ERROR)
37
+ # Where log messages go: to +logger+ when there is one, which then filters by its own level, and otherwise to
38
+ # standard output or error at +log_level+ and above. A nil +log_level+ without a logger logs nothing.
39
+ LogSettings = Struct.new(:logger, :log_level)
40
+
41
+ # The library-wide Files.logger and Files.log_level, read when each message is logged.
42
+ def self.global_log_settings
43
+ LogSettings.new(Files.logger, Files.log_level)
44
+ end
45
+
46
+ # The same values Files.log_level= accepts: nil, a level constant, or "debug" or "info".
47
+ def self.normalize_log_level(val)
48
+ val = { "debug" => LEVEL_DEBUG, "info" => LEVEL_INFO }.fetch(val, val)
49
+ if !val.nil? && ![ LEVEL_DEBUG, LEVEL_ERROR, LEVEL_INFO ].include?(val)
50
+ raise ArgumentError,
51
+ "log_level should only be set to `nil`, `debug` or `info`"
52
+ end
53
+ val
54
+ end
55
+
56
+ def self.log_error(message, data = {}, settings = global_log_settings)
57
+ if !settings.logger.nil? ||
58
+ (!settings.log_level.nil? && settings.log_level <= Files::LEVEL_ERROR)
40
59
  log_internal(message, data, color: :cyan, level: Files::LEVEL_ERROR,
41
- logger: Files.logger, out: $stderr
60
+ logger: settings.logger, out: $stderr
42
61
  )
43
62
  end
44
63
  end
45
64
 
46
- def self.log_info(message, data = {})
47
- if !Files.logger.nil? ||
48
- (!Files.log_level.nil? && Files.log_level <= Files::LEVEL_INFO)
65
+ def self.log_info(message, data = {}, settings = global_log_settings)
66
+ if !settings.logger.nil? ||
67
+ (!settings.log_level.nil? && settings.log_level <= Files::LEVEL_INFO)
49
68
  log_internal(message, data, color: :cyan, level: Files::LEVEL_INFO,
50
- logger: Files.logger, out: $stdout
69
+ logger: settings.logger, out: $stdout
51
70
  )
52
71
  end
53
72
  end
54
73
 
55
- def self.log_debug(message, data = {})
56
- if !Files.logger.nil? ||
57
- (!Files.log_level.nil? && Files.log_level <= Files::LEVEL_DEBUG)
74
+ def self.log_debug(message, data = {}, settings = global_log_settings)
75
+ if !settings.logger.nil? ||
76
+ (!settings.log_level.nil? && settings.log_level <= Files::LEVEL_DEBUG)
58
77
  log_internal(message, data, color: :blue, level: Files::LEVEL_DEBUG,
59
- logger: Files.logger, out: $stdout
78
+ logger: settings.logger, out: $stdout
60
79
  )
61
80
  end
62
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Files
4
- VERSION = "1.1.783"
4
+ VERSION = "1.1.784"
5
5
  end
@@ -344,6 +344,64 @@ RSpec.describe Files::ApiClient do
344
344
  end
345
345
  end
346
346
 
347
+ describe "client loggers" do
348
+ around do |example|
349
+ original = [ Files.logger, Files.log_level, Files.max_network_retries ]
350
+ Files.max_network_retries = 0
351
+ example.run
352
+ ensure
353
+ Files.logger, Files.log_level, Files.max_network_retries = original
354
+ end
355
+
356
+ it "logs each client's requests to its own logger without changing the library-wide settings" do
357
+ connection = Faraday.new do |builder|
358
+ builder.response :raise_error
359
+ builder.adapter :test do |stub|
360
+ (1..5).each do |id|
361
+ stub.get("/api/rest/v1/workspaces/#{id}") { [ 200, { "Content-Type" => "application/json" }, { id: id }.to_json ] }
362
+ end
363
+ stub.get("/api/rest/v1/workspaces/6") { [ 404, { "Content-Type" => "application/json" }, { error: "Not Found", type: "not-found" }.to_json ] }
364
+ end
365
+ end
366
+ global_output = StringIO.new
367
+ global_logger = Logger.new(global_output, level: Logger::INFO)
368
+ Files.logger = global_logger
369
+ Files.log_level = Files::LEVEL_INFO
370
+ a_output = StringIO.new
371
+ a_logger = Logger.new(a_output, level: Logger::INFO)
372
+ b_output = StringIO.new
373
+ b_logger = Logger.new(b_output, level: Logger::ERROR)
374
+ client_a = described_class.new(connection, logger: a_logger)
375
+ client_b = described_class.new(connection, logger: b_logger, log_level: Files::LEVEL_DEBUG)
376
+
377
+ Files::Workspace.find(1, {}, api_key: "key", client: client_a)
378
+ Files::Workspace.find(2, {}, api_key: "key", client: client_b)
379
+ Files::Workspace.find(3, {}, api_key: "key", client: client_a)
380
+
381
+ expect(a_output.string).to include("message=Request method=get num_retries=0 path=/workspaces/1", "message=Request method=get num_retries=0 path=/workspaces/3")
382
+ expect(a_output.string.scan(/message=Response .*status=200/).size).to eq(2)
383
+ expect(a_output.string).not_to include("/workspaces/2")
384
+ expect(b_output.string).to be_empty
385
+ expect(global_output.string).to be_empty
386
+ expect([ a_logger.level, b_logger.level ]).to eq([ Logger::INFO, Logger::ERROR ])
387
+ expect(Files.logger).to equal(global_logger)
388
+ expect(Files.log_level).to eq(Files::LEVEL_INFO)
389
+
390
+ expect { Files::Workspace.find(6, {}, api_key: "key", client: client_b) }.to raise_error(Files::NotFoundError)
391
+ expect(b_output.string).to include("message=API error status=404")
392
+ expect(a_output.string).not_to include("API error")
393
+ expect(global_output.string).to be_empty
394
+ expect([ a_logger.level, b_logger.level ]).to eq([ Logger::INFO, Logger::ERROR ])
395
+
396
+ Files::Workspace.find(4, {}, api_key: "key", client: described_class.new(connection))
397
+ expect(global_output.string).to include("message=Request method=get num_retries=0 path=/workspaces/4")
398
+
399
+ quiet_client = described_class.new(connection, logger: nil, log_level: nil)
400
+ expect { Files::Workspace.find(5, {}, api_key: "key", client: quiet_client) }.not_to output.to_stdout
401
+ expect(global_output.string).not_to include("/workspaces/5")
402
+ end
403
+ end
404
+
347
405
  describe "network timeouts" do
348
406
  around do |example|
349
407
  original = [ Files.open_timeout, Files.read_timeout ]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: files.com
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.783
4
+ version: 1.1.784
5
5
  platform: ruby
6
6
  authors:
7
7
  - files.com