google-cloud-logging 0.20.1 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,135 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ module Cloud
18
+ module Logging
19
+ class Middleware
20
+ ##
21
+ # The Google::Cloud::Logging::Logger instance
22
+ attr_reader :logger
23
+
24
+ ##
25
+ # Create a new AppEngine logging Middleware.
26
+ #
27
+ # @param app Rack application
28
+ #
29
+ # @param [Google::Cloud::Logging::Logger] logger A logger to be used by
30
+ # this middleware. The middleware will be interacting with the logger
31
+ # to track Stackdriver request trace ID. It also properly sets
32
+ # env["rack.logger"] to this assigned logger for accessing.
33
+ #
34
+ # @return [Google::Cloud::Logging::Middleware] A new
35
+ # Google::Cloud::Logging::Middleware instance
36
+ #
37
+ def initialize app, logger: nil
38
+ @app = app
39
+ @logger = logger
40
+ end
41
+
42
+ ##
43
+ # Rack middleware entry point. In most Rack based frameworks, a request
44
+ # is served by one thread. So entry point, we associate the GCP request
45
+ # trace_id with the current thread's object_id in logger. All the logs
46
+ # written by logger beyond this point will carry this request's
47
+ # trace_id. Untrack the trace_id with this thread upon exiting.
48
+ #
49
+ # @param [Hash] env Rack environment hash
50
+ #
51
+ # @return The response from downstream Rack app
52
+ #
53
+ def call env
54
+ env["rack.logger"] = logger
55
+ trace_id = extract_trace_id(env)
56
+ logger.add_trace_id trace_id
57
+
58
+ begin
59
+ @app.call env
60
+ ensure
61
+ logger.delete_trace_id
62
+ end
63
+ end
64
+
65
+ ##
66
+ # Extract the trace_id from HTTP request header
67
+ # HTTP_X_CLOUD_TRACE_CONTEXT.
68
+ #
69
+ # @return [String] The trace_id or nil if trace_id is empty.
70
+ def extract_trace_id env
71
+ trace_context = env["HTTP_X_CLOUD_TRACE_CONTEXT"].to_s
72
+ return nil if trace_context.empty?
73
+ trace_context.sub(%r{/.*}, "")
74
+ end
75
+
76
+ ##
77
+ # @private Extract information from current environment and construct
78
+ # the correct monitoring resource types and labels.
79
+ #
80
+ # If running from GAE, return resource:
81
+ # {
82
+ # type: "gae_app", {
83
+ # module_id: [GAE module name],
84
+ # version_id: [GAE module version]
85
+ # }
86
+ # }
87
+ # If running from GKE, return resource:
88
+ # {
89
+ # type: "container", {
90
+ # cluster_name: [GKE cluster name],
91
+ # namespace_id: [GKE namespace_id]
92
+ # }
93
+ # }
94
+ # If running from GCE, return resource:
95
+ # {
96
+ # type: "gce_instance", {
97
+ # instance_id: [GCE VM instance id],
98
+ # zone: [GCE vm group zone]
99
+ # }
100
+ # }
101
+ # Otherwise default to { type: "global" }, which means not associated
102
+ # with GCP.
103
+ #
104
+ # Reference https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
105
+ # for a full list of monitoring resources
106
+ #
107
+ # @return [Google::Cloud::Logging::Resource] An Resource object with
108
+ # correct type and labels
109
+ def self.build_monitoring_resource
110
+ type, labels =
111
+ if Core::Environment.gae?
112
+ ["gae_app", {
113
+ module_id: Core::Environment.gae_module_id,
114
+ version_id: Core::Environment.gae_module_version }]
115
+ elsif Core::Environment.gke?
116
+ ["container", {
117
+ cluster_name: Core::Environment.gke_cluster_name,
118
+ namespace_id: Core::Environment.gke_namespace_id || "default" }]
119
+ elsif Core::Environment.gce?
120
+ ["gce_instance", {
121
+ instance_id: Core::Environment.instance_id,
122
+ zone: Core::Environment.instance_zone }]
123
+ else
124
+ ["global", {}]
125
+ end
126
+
127
+ Google::Cloud::Logging::Resource.new.tap do |r|
128
+ r.type = type
129
+ r.labels = labels
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -14,14 +14,16 @@
14
14
 
15
15
 
16
16
  require "google/cloud/errors"
17
- require "google/cloud/core/gce"
17
+ require "google/cloud/core/environment"
18
18
  require "google/cloud/logging/service"
19
19
  require "google/cloud/logging/credentials"
20
20
  require "google/cloud/logging/entry"
21
21
  require "google/cloud/logging/resource_descriptor"
22
22
  require "google/cloud/logging/sink"
23
23
  require "google/cloud/logging/metric"
24
+ require "google/cloud/logging/async_writer"
24
25
  require "google/cloud/logging/logger"
26
+ require "google/cloud/logging/middleware"
25
27
 
26
28
  module Google
27
29
  module Cloud
@@ -37,10 +39,9 @@ module Google
37
39
  # {Google::Cloud#logging}.
38
40
  #
39
41
  # @example
40
- # require "google/cloud"
42
+ # require "google/cloud/logging"
41
43
  #
42
- # gcloud = Google::Cloud.new
43
- # logging = gcloud.logging
44
+ # logging = Google::Cloud::Logging.new
44
45
  # entries = logging.entries
45
46
  #
46
47
  # See Google::Cloud#logging
@@ -61,10 +62,12 @@ module Google
61
62
  # @return [String] the Google Cloud project ID
62
63
  #
63
64
  # @example
64
- # require "google/cloud"
65
+ # require "google/cloud/logging"
65
66
  #
66
- # gcloud = Google::Cloud.new "my-project", "/path/to/keyfile.json"
67
- # logging = gcloud.logging
67
+ # logging = Google::Cloud::Logging.new(
68
+ # project: "my-project",
69
+ # keyfile: "/path/to/keyfile.json"
70
+ # )
68
71
  #
69
72
  # logging.project #=> "my-project"
70
73
  #
@@ -78,7 +81,7 @@ module Google
78
81
  ENV["LOGGING_PROJECT"] ||
79
82
  ENV["GOOGLE_CLOUD_PROJECT"] ||
80
83
  ENV["GCLOUD_PROJECT"] ||
81
- Google::Cloud::Core::GCE.project_id
84
+ Google::Cloud::Core::Environment.project_id
82
85
  end
83
86
 
84
87
  ##
@@ -104,40 +107,36 @@ module Google
104
107
  # {Google::Cloud::Logging::Entry::List})
105
108
  #
106
109
  # @example
107
- # require "google/cloud"
110
+ # require "google/cloud/logging"
108
111
  #
109
- # gcloud = Google::Cloud.new
110
- # logging = gcloud.logging
112
+ # logging = Google::Cloud::Logging.new
111
113
  # entries = logging.entries
112
114
  # entries.each do |e|
113
115
  # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
114
116
  # end
115
117
  #
116
118
  # @example You can use a filter to narrow results to a single log.
117
- # require "google/cloud"
119
+ # require "google/cloud/logging"
118
120
  #
119
- # gcloud = Google::Cloud.new
120
- # logging = gcloud.logging
121
+ # logging = Google::Cloud::Logging.new
121
122
  # entries = logging.entries filter: "log:syslog"
122
123
  # entries.each do |e|
123
124
  # puts "[#{e.timestamp}] #{e.payload.inspect}"
124
125
  # end
125
126
  #
126
127
  # @example You can also order the results by timestamp.
127
- # require "google/cloud"
128
+ # require "google/cloud/logging"
128
129
  #
129
- # gcloud = Google::Cloud.new
130
- # logging = gcloud.logging
130
+ # logging = Google::Cloud::Logging.new
131
131
  # entries = logging.entries order: "timestamp desc"
132
132
  # entries.each do |e|
133
133
  # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
134
134
  # end
135
135
  #
136
136
  # @example Retrieve all log entries: (See {Entry::List#all})
137
- # require "google/cloud"
137
+ # require "google/cloud/logging"
138
138
  #
139
- # gcloud = Google::Cloud.new
140
- # logging = gcloud.logging
139
+ # logging = Google::Cloud::Logging.new
141
140
  # entries = logging.entries
142
141
  #
143
142
  # entries.all do |e|
@@ -184,10 +183,9 @@ module Google
184
183
  # @return [Google::Cloud::Logging::Entry] a new Entry instance
185
184
  #
186
185
  # @example
187
- # require "google/cloud"
186
+ # require "google/cloud/logging"
188
187
  #
189
- # gcloud = Google::Cloud.new
190
- # logging = gcloud.logging
188
+ # logging = Google::Cloud::Logging.new
191
189
  #
192
190
  # entry = logging.entry severity: :INFO, payload: "Job started."
193
191
  #
@@ -232,10 +230,9 @@ module Google
232
230
  # @return [Boolean] Returns `true` if the entries were written.
233
231
  #
234
232
  # @example
235
- # require "google/cloud"
233
+ # require "google/cloud/logging"
236
234
  #
237
- # gcloud = Google::Cloud.new
238
- # logging = gcloud.logging
235
+ # logging = Google::Cloud::Logging.new
239
236
  #
240
237
  # entry = logging.entry payload: "Job started.",
241
238
  # log_name: "my_app_log"
@@ -246,10 +243,9 @@ module Google
246
243
  # logging.write_entries entry
247
244
  #
248
245
  # @example Optionally pass log name, resource, and labels for entries.
249
- # require "google/cloud"
246
+ # require "google/cloud/logging"
250
247
  #
251
- # gcloud = Google::Cloud.new
252
- # logging = gcloud.logging
248
+ # logging = Google::Cloud::Logging.new
253
249
  #
254
250
  # entry1 = logging.entry payload: "Job started."
255
251
  # entry2 = logging.entry payload: "Job completed."
@@ -272,10 +268,83 @@ module Google
272
268
  true
273
269
  end
274
270
 
271
+ ##
272
+ # Creates an object that batches and transmits log entries
273
+ # asynchronously.
274
+ #
275
+ # Use this object to transmit log entries efficiently. It keeps a queue
276
+ # of log entries, and runs a background thread that transmits them to
277
+ # the logging service in batches. Generally, adding to the queue will
278
+ # not block.
279
+ #
280
+ # This object is thread-safe; it may accept write requests from
281
+ # multiple threads simultaneously, and will serialize them when
282
+ # executing in the background thread.
283
+ #
284
+ # @param [Integer] max_queue_size The maximum number of log entries
285
+ # that may be queued before write requests will begin to block.
286
+ # This provides back pressure in case the transmitting thread cannot
287
+ # keep up with requests.
288
+ #
289
+ # @example
290
+ # require "google/cloud/logging"
291
+ #
292
+ # logging = Google::Cloud::Logging.new
293
+ #
294
+ # async = logging.async_writer
295
+ #
296
+ # entry1 = logging.entry payload: "Job started."
297
+ # entry2 = logging.entry payload: "Job completed."
298
+ #
299
+ # labels = { job_size: "large", job_code: "red" }
300
+ # resource = logging.resource "gae_app",
301
+ # "module_id" => "1",
302
+ # "version_id" => "20150925t173233"
303
+ #
304
+ # async.write_entries [entry1, entry2],
305
+ # log_name: "my_app_log",
306
+ # resource: resource,
307
+ # labels: labels
308
+ #
309
+ def async_writer max_queue_size: AsyncWriter::DEFAULT_MAX_QUEUE_SIZE
310
+ AsyncWriter.new self, max_queue_size
311
+ end
312
+
313
+ ##
314
+ # Returns a shared AsyncWriter for this Project. If this method is
315
+ # called multiple times, it will return the same object.
316
+ #
317
+ # @example
318
+ # require "google/cloud/logging"
319
+ #
320
+ # logging = Google::Cloud::Logging.new
321
+ #
322
+ # async = logging.shared_async_writer
323
+ #
324
+ # entry1 = logging.entry payload: "Job started."
325
+ # entry2 = logging.entry payload: "Job completed."
326
+ #
327
+ # labels = { job_size: "large", job_code: "red" }
328
+ # resource = logging.resource "gae_app",
329
+ # "module_id" => "1",
330
+ # "version_id" => "20150925t173233"
331
+ #
332
+ # async.write_entries [entry1, entry2],
333
+ # log_name: "my_app_log",
334
+ # resource: resource,
335
+ # labels: labels
336
+ #
337
+ def shared_async_writer
338
+ @shared_async_writer ||= async_writer
339
+ end
340
+
275
341
  ##
276
342
  # Creates a logger instance that is API-compatible with Ruby's standard
277
343
  # library [Logger](http://ruby-doc.org/stdlib/libdoc/logger/rdoc).
278
344
  #
345
+ # The logger will create a new AsyncWriter object to transmit log
346
+ # entries on a background thread.
347
+ #
279
348
  # @param [String] log_name A log resource name to be associated with the
280
349
  # written log entries.
281
350
  # @param [Google::Cloud::Logging::Resource] resource The monitored
@@ -287,10 +356,9 @@ module Google
287
356
  # used in place of a ruby standard library logger object.
288
357
  #
289
358
  # @example
290
- # require "google/cloud"
359
+ # require "google/cloud/logging"
291
360
  #
292
- # gcloud = Google::Cloud.new
293
- # logging = gcloud.logging
361
+ # logging = Google::Cloud::Logging.new
294
362
  #
295
363
  # resource = logging.resource "gae_app",
296
364
  # module_id: "1",
@@ -300,7 +368,7 @@ module Google
300
368
  # logger.info "Job started."
301
369
  #
302
370
  def logger log_name, resource, labels = {}
303
- Logger.new self, log_name, resource, labels
371
+ Logger.new shared_async_writer, log_name, resource, labels
304
372
  end
305
373
 
306
374
  ##
@@ -317,10 +385,9 @@ module Google
317
385
  # were deleted.
318
386
  #
319
387
  # @example
320
- # require "google/cloud"
388
+ # require "google/cloud/logging"
321
389
  #
322
- # gcloud = Google::Cloud.new
323
- # logging = gcloud.logging
390
+ # logging = Google::Cloud::Logging.new
324
391
  # logging.delete_log "my_app_log"
325
392
  #
326
393
  def delete_log name
@@ -344,10 +411,9 @@ module Google
344
411
  # {Google::Cloud::Logging::ResourceDescriptor::List})
345
412
  #
346
413
  # @example
347
- # require "google/cloud"
414
+ # require "google/cloud/logging"
348
415
  #
349
- # gcloud = Google::Cloud.new
350
- # logging = gcloud.logging
416
+ # logging = Google::Cloud::Logging.new
351
417
  # resource_descriptors = logging.resource_descriptors
352
418
  # resource_descriptors.each do |rd|
353
419
  # label_keys = rd.labels.map(&:key).join(", ")
@@ -355,10 +421,9 @@ module Google
355
421
  # end
356
422
  #
357
423
  # @example Pagination:
358
- # require "google/cloud"
424
+ # require "google/cloud/logging"
359
425
  #
360
- # gcloud = Google::Cloud.new
361
- # logging = gcloud.logging
426
+ # logging = Google::Cloud::Logging.new
362
427
  # resource_descriptors = logging.resource_descriptors
363
428
  #
364
429
  # resource_descriptors.all do |rd|
@@ -375,13 +440,17 @@ module Google
375
440
  ##
376
441
  # Creates a new monitored resource instance.
377
442
  #
443
+ # @param [String] type The type of resource, as represented by a
444
+ # {ResourceDescriptor}.
445
+ # @param [Hash] labels A set of labels that can be used to describe
446
+ # instances of this monitored resource type.
447
+ #
378
448
  # @return [Google::Cloud::Logging::Resource]
379
449
  #
380
450
  # @example
381
- # require "google/cloud"
451
+ # require "google/cloud/logging"
382
452
  #
383
- # gcloud = Google::Cloud.new
384
- # logging = gcloud.logging
453
+ # logging = Google::Cloud::Logging.new
385
454
  #
386
455
  # resource = logging.resource "gae_app",
387
456
  # "module_id" => "1",
@@ -406,20 +475,18 @@ module Google
406
475
  # {Google::Cloud::Logging::Sink::List})
407
476
  #
408
477
  # @example
409
- # require "google/cloud"
478
+ # require "google/cloud/logging"
410
479
  #
411
- # gcloud = Google::Cloud.new
412
- # logging = gcloud.logging
480
+ # logging = Google::Cloud::Logging.new
413
481
  # sinks = logging.sinks
414
482
  # sinks.each do |s|
415
483
  # puts "#{s.name}: #{s.filter} -> #{s.destination}"
416
484
  # end
417
485
  #
418
486
  # @example Retrieve all sinks: (See {Sink::List#all})
419
- # require "google/cloud"
487
+ # require "google/cloud/logging"
420
488
  #
421
- # gcloud = Google::Cloud.new
422
- # logging = gcloud.logging
489
+ # logging = Google::Cloud::Logging.new
423
490
  # sinks = logging.sinks
424
491
  #
425
492
  # sinks.all do |s|
@@ -477,11 +544,9 @@ module Google
477
544
  # @return [Google::Cloud::Logging::Sink] a project sink
478
545
  #
479
546
  # @example
480
- # require "google/cloud"
547
+ # require "google/cloud/storage"
481
548
  #
482
- # gcloud = Google::Cloud.new
483
- # logging = gcloud.logging
484
- # storage = gcloud.storage
549
+ # storage = Google::Cloud::Storage.new
485
550
  #
486
551
  # bucket = storage.create_bucket "my-logs-bucket"
487
552
  #
@@ -489,6 +554,10 @@ module Google
489
554
  # email = "cloud-logs@google.com"
490
555
  # bucket.acl.add_owner "group-#{email}"
491
556
  #
557
+ # require "google/cloud/logging"
558
+ #
559
+ # logging = Google::Cloud::Logging.new
560
+ #
492
561
  # sink = logging.create_sink "my-sink",
493
562
  # "storage.googleapis.com/#{bucket.id}"
494
563
  #
@@ -509,17 +578,15 @@ module Google
509
578
  # does not exist.
510
579
  #
511
580
  # @example
512
- # require "google/cloud"
581
+ # require "google/cloud/logging"
513
582
  #
514
- # gcloud = Google::Cloud.new
515
- # logging = gcloud.logging
583
+ # logging = Google::Cloud::Logging.new
516
584
  # sink = logging.sink "existing-sink"
517
585
  #
518
586
  # @example By default `nil` will be returned if the sink does not exist.
519
- # require "google/cloud"
587
+ # require "google/cloud/logging"
520
588
  #
521
- # gcloud = Google::Cloud.new
522
- # logging = gcloud.logging
589
+ # logging = Google::Cloud::Logging.new
523
590
  # sink = logging.sink "non-existing-sink" #=> nil
524
591
  #
525
592
  def sink sink_name
@@ -543,20 +610,18 @@ module Google
543
610
  # {Google::Cloud::Logging::Metric::List})
544
611
  #
545
612
  # @example
546
- # require "google/cloud"
613
+ # require "google/cloud/logging"
547
614
  #
548
- # gcloud = Google::Cloud.new
549
- # logging = gcloud.logging
615
+ # logging = Google::Cloud::Logging.new
550
616
  # metrics = logging.metrics
551
617
  # metrics.each do |m|
552
618
  # puts "#{m.name}: #{m.filter}"
553
619
  # end
554
620
  #
555
621
  # @example Retrieve all metrics: (See {Metric::List#all})
556
- # require "google/cloud"
622
+ # require "google/cloud/logging"
557
623
  #
558
- # gcloud = Google::Cloud.new
559
- # logging = gcloud.logging
624
+ # logging = Google::Cloud::Logging.new
560
625
  # metrics = logging.metrics
561
626
  #
562
627
  # metrics.all do |m|
@@ -591,10 +656,9 @@ module Google
591
656
  # @return [Google::Cloud::Logging::Metric]
592
657
  #
593
658
  # @example
594
- # require "google/cloud"
659
+ # require "google/cloud/logging"
595
660
  #
596
- # gcloud = Google::Cloud.new
597
- # logging = gcloud.logging
661
+ # logging = Google::Cloud::Logging.new
598
662
  # metric = logging.create_metric "errors", "severity>=ERROR"
599
663
  #
600
664
  def create_metric name, filter, description: nil
@@ -613,17 +677,15 @@ module Google
613
677
  # does not exist.
614
678
  #
615
679
  # @example
616
- # require "google/cloud"
680
+ # require "google/cloud/logging"
617
681
  #
618
- # gcloud = Google::Cloud.new
619
- # logging = gcloud.logging
682
+ # logging = Google::Cloud::Logging.new
620
683
  # metric = logging.metric "existing_metric"
621
684
  #
622
685
  # @example By default `nil` will be returned if metric does not exist.
623
- # require "google/cloud"
686
+ # require "google/cloud/logging"
624
687
  #
625
- # gcloud = Google::Cloud.new
626
- # logging = gcloud.logging
688
+ # logging = Google::Cloud::Logging.new
627
689
  # metric = logging.metric "non_existing_metric" #=> nil
628
690
  #
629
691
  def metric name