fluent-plugin-oci-logging-analytics 2.0.0 → 2.0.4
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
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2c10b68eefbf373de236156362383500f9746a9
|
4
|
+
data.tar.gz: 6ad63e3893634f360387c68b03248291d787d33f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcb93cdf4da13e23101127320bec26bb96ac3426e2fe34402591febfc1e0ab8494a253e8c089f0bcd13aafea35b740ea353ee164213d89d415fe93a07d8764e2
|
7
|
+
data.tar.gz: 83115a796e9baf6311c3d3da4f9f137fdbd4cbb74bb52f10a3686cc8441f26315c38522bb32c1acc06652aaae92bd7a1adff643f555df91de11a4b1e84487355
|
data/lib/fluent/dto/logEvents.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
## Copyright (c) 2021, 2022 Oracle and/or its affiliates.
|
2
|
+
## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
1
3
|
|
2
4
|
class LogEvents
|
3
5
|
attr_accessor :entityId, :entityType, :logSourceName, :logPath, :logRecords , :metadata
|
@@ -1,11 +1,13 @@
|
|
1
1
|
class MetricsLabels
|
2
|
-
attr_accessor :tag, :logGroupId, :logSourceName, :logSet, :
|
2
|
+
attr_accessor :tag, :logGroupId, :logSourceName, :logSet, :invalid_reason, :records_valid, :records_per_tag, :latency
|
3
3
|
def initialize
|
4
4
|
@tag = nil
|
5
5
|
@logGroupId = nil
|
6
6
|
@logSourceName = nil
|
7
7
|
@logSet = nil
|
8
|
-
@
|
8
|
+
@invalid_reason = nil
|
9
9
|
@records_valid = 0
|
10
|
+
@records_per_tag = 0
|
11
|
+
@latency = 0
|
10
12
|
end
|
11
13
|
end
|
@@ -6,36 +6,36 @@ require 'singleton'
|
|
6
6
|
|
7
7
|
class PrometheusMetrics
|
8
8
|
include Singleton
|
9
|
-
attr_accessor :records_received, :records_valid, :
|
10
|
-
:bytes_received, :bytes_posted, :
|
9
|
+
attr_accessor :records_received, :records_valid, :records_invalid, :records_error, :records_posted,
|
10
|
+
:bytes_received, :bytes_posted, :chunk_time_to_receive, :chunk_time_to_upload
|
11
11
|
def initialize
|
12
12
|
createMetrics
|
13
13
|
registerMetrics
|
14
14
|
end
|
15
15
|
def createMetrics
|
16
16
|
gauge = Prometheus::Client::Gauge
|
17
|
-
@records_received = gauge.new(:
|
18
|
-
@records_valid = gauge.new(:
|
19
|
-
@
|
20
|
-
@records_error = gauge.new(:
|
21
|
-
@records_posted = gauge.new(:
|
22
|
-
|
23
|
-
|
17
|
+
@records_received = gauge.new(:oci_la_fluentd_output_plugin_records_received, docstring: 'Number of records received by the OCI Logging Analytics Fluentd output plugin.', labels: [:tag,:oci_la_log_group_id,:oci_la_log_source_name,:oci_la_log_set])
|
18
|
+
@records_valid = gauge.new(:oci_la_fluentd_output_plugin_records_valid, docstring: 'Number of valid records received by the OCI Logging Analytics Fluentd output plugin.', labels: [:tag,:oci_la_log_group_id,:oci_la_log_source_name,:oci_la_log_set])
|
19
|
+
@records_invalid = gauge.new(:oci_la_fluentd_output_plugin_records_invalid, docstring: 'Number of invalid records received by the OCI Logging Analytics Fluentd output plugin.', labels: [:tag,:oci_la_log_group_id,:oci_la_log_source_name,:oci_la_log_set,:reason])
|
20
|
+
@records_error = gauge.new(:oci_la_fluentd_output_plugin_records_post_error, docstring: 'Number of records failed posting to OCI Logging Analytics by the Fluentd output plugin.', labels: [:tag,:oci_la_log_group_id,:oci_la_log_source_name,:oci_la_log_set,:error_code, :reason])
|
21
|
+
@records_posted = gauge.new(:oci_la_fluentd_output_plugin_records_post_success, docstring: 'Number of records posted by the OCI Logging Analytics Fluentd output plugin.', labels: [:tag,:oci_la_log_group_id,:oci_la_log_source_name,:oci_la_log_set])
|
22
|
+
#@bytes_received = gauge.new(:oci_la_bytes_received, docstring: '...', labels: [:tag])
|
23
|
+
#@bytes_posted = gauge.new(:oci_la_bytes_posted, docstring: '...', labels: [:oci_la_log_group_id])
|
24
24
|
histogram = Prometheus::Client::Histogram
|
25
|
-
@
|
26
|
-
@
|
25
|
+
@chunk_time_to_receive = histogram.new(:oci_la_fluentd_output_plugin_chunk_time_to_receive, docstring: 'Average time taken by Fluentd to deliver the collected records from Input plugin to OCI Logging Analytics output plugin.', labels: [:tag])
|
26
|
+
@chunk_time_to_upload = histogram.new(:oci_la_fluentd_output_plugin_chunk_time_to_post, docstring: 'Average time taken for posting the received records to OCI Logging Analytics by the Fluentd output plugin.', labels: [:oci_la_log_group_id])
|
27
27
|
end
|
28
28
|
|
29
29
|
def registerMetrics
|
30
30
|
registry = Prometheus::Client.registry
|
31
|
-
registry.register(@records_received) unless registry.exist?('
|
32
|
-
registry.register(@records_valid) unless registry.exist?('
|
33
|
-
registry.register(@
|
34
|
-
registry.register(@records_error) unless registry.exist?('
|
35
|
-
registry.register(@records_posted) unless registry.exist?('
|
36
|
-
registry.register(@bytes_received) unless registry.exist?('
|
37
|
-
registry.register(@bytes_posted) unless registry.exist?('
|
38
|
-
registry.register(@
|
39
|
-
registry.register(@
|
31
|
+
registry.register(@records_received) unless registry.exist?('oci_la_fluentd_output_plugin_records_received')
|
32
|
+
registry.register(@records_valid) unless registry.exist?('oci_la_fluentd_output_plugin_records_valid')
|
33
|
+
registry.register(@records_invalid) unless registry.exist?('oci_la_fluentd_output_plugin_records_invalid')
|
34
|
+
registry.register(@records_error) unless registry.exist?('oci_la_fluentd_output_plugin_records_post_error')
|
35
|
+
registry.register(@records_posted) unless registry.exist?('oci_la_fluentd_output_plugin_records_post_success')
|
36
|
+
#registry.register(@bytes_received) unless registry.exist?('oci_la_bytes_received')
|
37
|
+
#registry.register(@bytes_posted) unless registry.exist?('oci_la_bytes_valid')
|
38
|
+
registry.register(@chunk_time_to_receive) unless registry.exist?('oci_la_fluentd_output_plugin_chunk_time_to_receive')
|
39
|
+
registry.register(@chunk_time_to_upload) unless registry.exist?('oci_la_fluentd_output_plugin_chunk_time_to_post')
|
40
40
|
end
|
41
41
|
end
|
@@ -1,13 +1,53 @@
|
|
1
|
-
## Copyright (c) 2021 Oracle and/or its affiliates.
|
1
|
+
## Copyright (c) 2021, 2022 Oracle and/or its affiliates.
|
2
2
|
## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
3
3
|
|
4
4
|
require 'fluent/plugin/output'
|
5
5
|
require "benchmark"
|
6
6
|
require 'zip'
|
7
|
-
|
7
|
+
|
8
8
|
require 'logger'
|
9
9
|
require_relative '../dto/logEventsJson'
|
10
10
|
require_relative '../dto/logEvents'
|
11
|
+
require_relative '../metrics/prometheusMetrics'
|
12
|
+
require_relative '../metrics/metricsLabels'
|
13
|
+
|
14
|
+
# Import only specific OCI modules to improve load times and reduce the memory requirements.
|
15
|
+
require 'oci/auth/auth'
|
16
|
+
require 'oci/log_analytics/log_analytics'
|
17
|
+
require 'oci/log_analytics/log_analytics_client'
|
18
|
+
|
19
|
+
# Workaround until OCI SDK releases a proper fix to load only specific service related modules/client.
|
20
|
+
require 'oci/api_client'
|
21
|
+
require 'oci/api_client_proxy_settings'
|
22
|
+
require 'oci/config'
|
23
|
+
require 'oci/config_file_loader'
|
24
|
+
require 'oci/errors'
|
25
|
+
require 'oci/global_context'
|
26
|
+
require 'oci/internal/internal'
|
27
|
+
require 'oci/regions'
|
28
|
+
require 'oci/regions_definitions'
|
29
|
+
require 'oci/response_headers'
|
30
|
+
require 'oci/response'
|
31
|
+
require 'oci/base_signer'
|
32
|
+
require 'oci/signer'
|
33
|
+
require 'oci/version'
|
34
|
+
require 'oci/waiter'
|
35
|
+
require 'oci/retry/retry'
|
36
|
+
require 'oci/object_storage/object_storage'
|
37
|
+
|
38
|
+
module OCI
|
39
|
+
class << self
|
40
|
+
attr_accessor :sdk_name
|
41
|
+
|
42
|
+
# Defines the logger used for debugging for the OCI module.
|
43
|
+
# For example, log to STDOUT by setting this to Logger.new(STDOUT).
|
44
|
+
#
|
45
|
+
# @return [Logger]
|
46
|
+
attr_accessor :logger
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
OracleBMC = OCI
|
11
51
|
|
12
52
|
module Fluent::Plugin
|
13
53
|
class OutOracleOCILogAnalytics < Output
|
@@ -15,8 +55,25 @@ module Fluent::Plugin
|
|
15
55
|
helpers :thread, :event_emitter
|
16
56
|
|
17
57
|
MAX_FILES_PER_ZIP = 100
|
58
|
+
METRICS_INVALID_REASON_MESSAGE = "MISSING_FIELD_MESSAGE"
|
59
|
+
METRICS_INVALID_REASON_LOG_GROUP_ID = "MISSING_OCI_LA_LOG_GROUP_ID_FIELD"
|
60
|
+
METRICS_INVALID_REASON_LOG_SOURCE_NAME = "MISSING_OCI_LA_LOG_SOURCE_NAME_FIELD"
|
61
|
+
|
62
|
+
METRICS_SERVICE_ERROR_REASON_400 = "INVALID_PARAMETER"
|
63
|
+
METRICS_SERVICE_ERROR_REASON_401 = "AUTHENTICATION_FAILED"
|
64
|
+
METRICS_SERVICE_ERROR_REASON_404 = "AUTHORIZATION_FAILED"
|
65
|
+
METRICS_SERVICE_ERROR_REASON_429 = "TOO_MANY_REQUESTES"
|
66
|
+
METRICS_SERVICE_ERROR_REASON_500 = "INTERNAL_SERVER_ERROR"
|
67
|
+
METRICS_SERVICE_ERROR_REASON_502 = "BAD_GATEWAY"
|
68
|
+
METRICS_SERVICE_ERROR_REASON_503 = "SERVICE_UNAVAILABLE"
|
69
|
+
METRICS_SERVICE_ERROR_REASON_504 = "GATEWAY_TIMEOUT"
|
70
|
+
METRICS_SERVICE_ERROR_REASON_505 = "HTTP_VERSION_NOT_SUPPORTED"
|
71
|
+
METRICS_SERVICE_ERROR_REASON_UNKNOWN = "UNKNOWN_ERROR"
|
72
|
+
|
73
|
+
|
18
74
|
@@logger = nil
|
19
75
|
@@loganalytics_client = nil
|
76
|
+
@@prometheusMetrics = nil
|
20
77
|
@@logger_config_errors = []
|
21
78
|
|
22
79
|
|
@@ -214,6 +271,7 @@ module Fluent::Plugin
|
|
214
271
|
|
215
272
|
def configure(conf)
|
216
273
|
super
|
274
|
+
@@prometheusMetrics = PrometheusMetrics.instance
|
217
275
|
initialize_logger
|
218
276
|
|
219
277
|
initialize_loganalytics_client
|
@@ -466,32 +524,36 @@ module Fluent::Plugin
|
|
466
524
|
|
467
525
|
def is_valid_record(record_hash,record)
|
468
526
|
begin
|
527
|
+
invalid_reason = nil
|
469
528
|
if !record_hash.has_key?("message")
|
529
|
+
invalid_reason = OutOracleOCILogAnalytics::METRICS_INVALID_REASON_MESSAGE
|
470
530
|
if record_hash.has_key?("tag")
|
471
531
|
@@logger.warn {"Invalid records associated with tag : #{record["tag"]}. 'message' field is not present in the record."}
|
472
532
|
else
|
473
533
|
@@logger.info {"InvalidRecord: #{record}"}
|
474
534
|
@@logger.warn {"Invalid record. 'message' field is not present in the record."}
|
475
535
|
end
|
476
|
-
return false
|
536
|
+
return false,invalid_reason
|
477
537
|
elsif !record_hash.has_key?("oci_la_log_group_id") || !is_valid(record["oci_la_log_group_id"])
|
538
|
+
invalid_reason = OutOracleOCILogAnalytics::METRICS_INVALID_REASON_LOG_GROUP_ID
|
478
539
|
if record_hash.has_key?("tag")
|
479
540
|
@@logger.warn {"Invalid records associated with tag : #{record["tag"]}.'oci_la_log_group_id' must not be empty.
|
480
541
|
Skipping all the records associated with the tag"}
|
481
542
|
else
|
482
543
|
@@logger.warn {"Invalid record.'oci_la_log_group_id' must not be empty"}
|
483
544
|
end
|
484
|
-
return false
|
545
|
+
return false,invalid_reason
|
485
546
|
elsif !record_hash.has_key?("oci_la_log_source_name") || !is_valid(record["oci_la_log_source_name"])
|
547
|
+
invalid_reason = OutOracleOCILogAnalytics::METRICS_INVALID_REASON_LOG_SOURCE_NAME
|
486
548
|
if record_hash.has_key?("tag")
|
487
549
|
@@logger.warn {"Invalid records associated with tag : #{record["tag"]}.'oci_la_log_source_name' must not be empty.
|
488
550
|
Skipping all the records associated with the tag"}
|
489
551
|
else
|
490
552
|
@@logger.warn {"Invalid record.'oci_la_log_source_name' must not be empty"}
|
491
553
|
end
|
492
|
-
return false
|
554
|
+
return false,invalid_reason
|
493
555
|
else
|
494
|
-
return true
|
556
|
+
return true,invalid_reason
|
495
557
|
end
|
496
558
|
end
|
497
559
|
end
|
@@ -542,6 +604,11 @@ module Fluent::Plugin
|
|
542
604
|
current_f, current_s = current.to_f, current.strftime("%Y%m%dT%H%M%S%9NZ")
|
543
605
|
records = []
|
544
606
|
count = 0
|
607
|
+
latency = 0
|
608
|
+
records_per_tag = 0
|
609
|
+
|
610
|
+
tag_metrics_set = Hash.new
|
611
|
+
logGroup_labels_set = Hash.new
|
545
612
|
|
546
613
|
invalid_tag_set = Set.new
|
547
614
|
incoming_records_per_tag = Hash.new
|
@@ -549,130 +616,166 @@ module Fluent::Plugin
|
|
549
616
|
tags_per_logGroupId = Hash.new
|
550
617
|
tag_logSet_map = Hash.new
|
551
618
|
tag_metadata_map = Hash.new
|
619
|
+
incoming_records = 0
|
552
620
|
|
553
621
|
chunk.each do |time, record|
|
554
|
-
|
622
|
+
incoming_records += 1
|
623
|
+
metricsLabels = MetricsLabels.new
|
555
624
|
if !record.nil?
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
625
|
+
begin
|
626
|
+
record_hash = record.keys.map {|x| [x,true]}.to_h
|
627
|
+
is_tag_exists = false
|
628
|
+
if record_hash.has_key?("tag") && is_valid(record["tag"])
|
629
|
+
is_tag_exists = true
|
630
|
+
metricsLabels.tag = record["tag"]
|
631
|
+
end
|
561
632
|
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
end
|
567
|
-
#For any given tag, if one record fails (mandatory fields validation) then all the records from that source will be ignored
|
568
|
-
if is_tag_exists && invalid_tag_set.include?(record["tag"])
|
569
|
-
invalid_records_per_tag[record["tag"]] += 1
|
570
|
-
next #This tag is already present in the invalid_tag_set, so ignoring the message.
|
571
|
-
end
|
572
|
-
#Setting tag/default value for oci_la_log_path, when not provided in config file.
|
573
|
-
if !record_hash.has_key?("oci_la_log_path") || !is_valid(record["oci_la_log_path"])
|
574
|
-
if is_tag_exists
|
575
|
-
record["oci_la_log_path"] = record["tag"]
|
576
|
-
else
|
577
|
-
record["oci_la_log_path"] = 'UNDEFINED'
|
633
|
+
if is_tag_exists && incoming_records_per_tag.has_key?(record["tag"])
|
634
|
+
incoming_records_per_tag[record["tag"]] += 1
|
635
|
+
elsif is_tag_exists
|
636
|
+
incoming_records_per_tag[record["tag"]] = 1
|
578
637
|
end
|
579
|
-
|
638
|
+
#For any given tag, if one record fails (mandatory fields validation) then all the records from that source will be ignored
|
639
|
+
if is_tag_exists && invalid_tag_set.include?(record["tag"])
|
640
|
+
invalid_records_per_tag[record["tag"]] += 1
|
641
|
+
next #This tag is already present in the invalid_tag_set, so ignoring the message.
|
642
|
+
end
|
643
|
+
#Setting tag/default value for oci_la_log_path, when not provided in config file.
|
644
|
+
if !record_hash.has_key?("oci_la_log_path") || !is_valid(record["oci_la_log_path"])
|
645
|
+
if is_tag_exists
|
646
|
+
record["oci_la_log_path"] = record["tag"]
|
647
|
+
else
|
648
|
+
record["oci_la_log_path"] = 'UNDEFINED'
|
649
|
+
end
|
650
|
+
end
|
580
651
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
652
|
+
#Extracting oci_la_log_set when oci_la_log_set_key and oci_la_log_set_ext_regex is provided.
|
653
|
+
#1) oci_la_log_set param is not provided in config file and above logic not executed.
|
654
|
+
#2) Valid oci_la_log_set_key + No oci_la_log_set_ext_regex
|
655
|
+
#a) Valid key available in record with oci_la_log_set_key corresponding value (oci_la_log_set_key is a key in config file) --> oci_la_log_set
|
656
|
+
#b) No Valid key available in record with oci_la_log_set_key corresponding value --> nil
|
657
|
+
#3) Valid key available in record with oci_la_log_set_key corresponding value + Valid oci_la_log_set_ext_regex
|
658
|
+
#a) Parse success --> parsed oci_la_log_set
|
659
|
+
#b) Parse failure --> nil (as oci_la_log_set value)
|
660
|
+
#4) No oci_la_log_set_key --> do nothing --> nil
|
661
|
+
|
662
|
+
#Extracting oci_la_log_set when oci_la_log_set and oci_la_log_set_ext_regex is provided.
|
663
|
+
#1) Valid oci_la_log_set + No oci_la_log_set_ext_regex --> oci_la_log_set
|
664
|
+
#2) Valid oci_la_log_set + Valid oci_la_log_set_ext_regex
|
665
|
+
#a) Parse success --> parsed oci_la_log_set
|
666
|
+
#b) Parse failure --> nil (as oci_la_log_set value)
|
667
|
+
#3) No oci_la_log_set --> do nothing --> nil
|
668
|
+
|
669
|
+
unparsed_logSet = nil
|
670
|
+
processed_logSet = nil
|
671
|
+
if is_tag_exists && tag_logSet_map.has_key?(record["tag"])
|
672
|
+
record["oci_la_log_set"] = tag_logSet_map[record["tag"]]
|
673
|
+
else
|
674
|
+
if record_hash.has_key?("oci_la_log_set_key")
|
675
|
+
if is_valid(record["oci_la_log_set_key"]) && record_hash.has_key?(record["oci_la_log_set_key"])
|
676
|
+
if is_valid(record[record["oci_la_log_set_key"]])
|
677
|
+
unparsed_logSet = record[record["oci_la_log_set_key"]]
|
678
|
+
processed_logSet = get_or_parse_logSet(unparsed_logSet,record, record_hash,is_tag_exists)
|
679
|
+
end
|
608
680
|
end
|
609
681
|
end
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
682
|
+
if !is_valid(processed_logSet) && record_hash.has_key?("oci_la_log_set")
|
683
|
+
if is_valid(record["oci_la_log_set"])
|
684
|
+
unparsed_logSet = record["oci_la_log_set"]
|
685
|
+
processed_logSet = get_or_parse_logSet(unparsed_logSet,record, record_hash,is_tag_exists)
|
686
|
+
end
|
615
687
|
end
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
688
|
+
record["oci_la_log_set"] = processed_logSet
|
689
|
+
tag_logSet_map[record["tag"]] = processed_logSet
|
690
|
+
end
|
691
|
+
is_valid, metricsLabels.invalid_reason = is_valid_record(record_hash,record)
|
620
692
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
invalid_records_per_tag[record["tag"]] = 1
|
625
|
-
end
|
626
|
-
next
|
627
|
-
end
|
628
|
-
#This will check for null or empty messages and only that record will be ignored.
|
629
|
-
if !is_valid(record["message"])
|
630
|
-
if is_tag_exists
|
631
|
-
@@logger.warn {"'message' field has empty value, Skipping records associated with tag : #{record["tag"]}."}
|
632
|
-
if invalid_records_per_tag.has_key?(record["tag"])
|
633
|
-
invalid_records_per_tag[record["tag"]] += 1
|
634
|
-
else
|
693
|
+
unless is_valid
|
694
|
+
if is_tag_exists
|
695
|
+
invalid_tag_set.add(record["tag"])
|
635
696
|
invalid_records_per_tag[record["tag"]] = 1
|
636
697
|
end
|
698
|
+
next
|
699
|
+
end
|
700
|
+
metricsLabels.logGroupId = record["oci_la_log_group_id"]
|
701
|
+
metricsLabels.logSourceName = record["oci_la_log_source_name"]
|
702
|
+
if record["oci_la_log_set"] != nil
|
703
|
+
metricsLabels.logSet = record["oci_la_log_set"]
|
704
|
+
end
|
705
|
+
#This will check for null or empty messages and only that record will be ignored.
|
706
|
+
if !is_valid(record["message"])
|
707
|
+
metricsLabels.invalid_reason = OutOracleOCILogAnalytics::METRICS_INVALID_REASON_MESSAGE
|
708
|
+
if is_tag_exists
|
709
|
+
@@logger.warn {"'message' field has empty value, Skipping records associated with tag : #{record["tag"]}."}
|
710
|
+
if invalid_records_per_tag.has_key?(record["tag"])
|
711
|
+
invalid_records_per_tag[record["tag"]] += 1
|
712
|
+
else
|
713
|
+
invalid_records_per_tag[record["tag"]] = 1
|
714
|
+
end
|
715
|
+
else
|
716
|
+
@@logger.warn {"'message' field has empty value, Skipping record."}
|
717
|
+
end
|
718
|
+
next
|
637
719
|
else
|
638
|
-
|
720
|
+
record["message"] = json_message_handler(record["message"])
|
639
721
|
end
|
640
|
-
next
|
641
|
-
else
|
642
|
-
record["message"] = json_message_handler(record["message"])
|
643
|
-
end
|
644
722
|
|
645
|
-
|
646
|
-
|
647
|
-
|
723
|
+
if record_hash.has_key?("kubernetes")
|
724
|
+
record["oci_la_metadata"] = get_kubernetes_metadata(record["oci_la_metadata"],record)
|
725
|
+
end
|
648
726
|
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
727
|
+
if tag_metadata_map.has_key?(record["tag"])
|
728
|
+
record["oci_la_metadata"] = tag_metadata_map[record["tag"]]
|
729
|
+
else
|
730
|
+
if record_hash.has_key?("oci_la_metadata")
|
731
|
+
record["oci_la_metadata"] = get_valid_metadata(record["oci_la_metadata"])
|
732
|
+
tags_per_logGroupId[record["tag"]] = record["oci_la_metadata"]
|
733
|
+
else
|
734
|
+
tags_per_logGroupId[record["tag"]] = nil
|
735
|
+
end
|
736
|
+
end
|
659
737
|
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
738
|
+
if is_tag_exists
|
739
|
+
if tags_per_logGroupId.has_key?(record["oci_la_log_group_id"])
|
740
|
+
if !tags_per_logGroupId[record["oci_la_log_group_id"]].include?(record["tag"])
|
741
|
+
tags_per_logGroupId[record["oci_la_log_group_id"]] += ", "+record["tag"]
|
742
|
+
end
|
743
|
+
else
|
744
|
+
tags_per_logGroupId[record["oci_la_log_group_id"]] = record["tag"]
|
745
|
+
end
|
664
746
|
end
|
665
|
-
else
|
666
|
-
tags_per_logGroupId[record["oci_la_log_group_id"]] = record["tag"]
|
667
|
-
end
|
668
|
-
end
|
669
747
|
|
670
|
-
|
748
|
+
records << record
|
749
|
+
ensure
|
750
|
+
# To get chunk_time_to_receive metrics per tag, corresponding latency and total records are calculated
|
751
|
+
if tag_metrics_set.has_key?(record["tag"])
|
752
|
+
metricsLabels = tag_metrics_set[record["tag"]]
|
753
|
+
latency = metricsLabels.latency
|
754
|
+
records_per_tag = metricsLabels.records_per_tag
|
755
|
+
else
|
756
|
+
latency = 0
|
757
|
+
records_per_tag = 0
|
758
|
+
end
|
759
|
+
latency += (current_f - time)
|
760
|
+
records_per_tag += 1
|
761
|
+
metricsLabels.latency = latency
|
762
|
+
metricsLabels.records_per_tag = records_per_tag
|
763
|
+
tag_metrics_set[record["tag"]] = metricsLabels
|
764
|
+
if record["oci_la_log_group_id"] != nil && !logGroup_labels_set.has_key?(record["oci_la_log_group_id"])
|
765
|
+
logGroup_labels_set[record["oci_la_log_group_id"]] = metricsLabels
|
766
|
+
end
|
767
|
+
end
|
671
768
|
else
|
672
769
|
@@logger.trace {"Record is nil, ignoring the record"}
|
673
770
|
end
|
674
771
|
end
|
675
772
|
@@logger.debug {"records.length:#{records.length}"}
|
773
|
+
|
774
|
+
tag_metrics_set.each do |tag,metricsLabels|
|
775
|
+
latency_avg = (metricsLabels.latency / metricsLabels.records_per_tag).round(3)
|
776
|
+
@@prometheusMetrics.chunk_time_to_receive.observe(latency_avg, labels: { tag: tag})
|
777
|
+
end
|
778
|
+
|
676
779
|
lrpes_for_logGroupId = {}
|
677
780
|
records.group_by{|record|
|
678
781
|
oci_la_log_group_id = record['oci_la_log_group_id']
|
@@ -683,29 +786,62 @@ module Fluent::Plugin
|
|
683
786
|
rescue => ex
|
684
787
|
@@logger.error {"Error occurred while grouping records by oci_la_log_group_id:#{ex.inspect}"}
|
685
788
|
end
|
686
|
-
return incoming_records_per_tag,invalid_records_per_tag,tags_per_logGroupId,lrpes_for_logGroupId
|
789
|
+
return incoming_records_per_tag,invalid_records_per_tag,tag_metrics_set,logGroup_labels_set,tags_per_logGroupId,lrpes_for_logGroupId
|
687
790
|
end
|
688
791
|
# main entry point for FluentD's flush_threads, which get invoked
|
689
792
|
# when a chunk is ready for flushing (see chunk limits and flush_intervals)
|
690
793
|
def write(chunk)
|
691
794
|
@@logger.info {"Received new chunk, started processing ..."}
|
692
|
-
|
693
|
-
metrics["count"] = 0
|
694
|
-
metrics["event"] = "zipping"
|
695
|
-
metrics["bytes_in"] = chunk.bytesize
|
696
|
-
metrics['records_dropped'] = 0
|
795
|
+
#@@prometheusMetrics.bytes_received.set(chunk.bytesize, labels: { tag: nil})
|
697
796
|
begin
|
698
797
|
# 1) Create an in-memory zipfile for the given FluentD chunk
|
699
798
|
# 2) Synchronization has been removed. See EMCLAS-28675
|
700
799
|
|
701
800
|
begin
|
702
801
|
lrpes_for_logGroupId = {}
|
703
|
-
incoming_records_per_tag,invalid_records_per_tag,tags_per_logGroupId,lrpes_for_logGroupId = group_by_logGroupId(chunk)
|
802
|
+
incoming_records_per_tag,invalid_records_per_tag,tag_metrics_set,logGroup_labels_set,tags_per_logGroupId,lrpes_for_logGroupId = group_by_logGroupId(chunk)
|
704
803
|
valid_message_per_tag = Hash.new
|
804
|
+
logGroup_metrics_map = Hash.new
|
805
|
+
metricsLabels_array = []
|
806
|
+
|
705
807
|
incoming_records_per_tag.each do |key,value|
|
706
808
|
dropped_messages = (invalid_records_per_tag.has_key?(key)) ? invalid_records_per_tag[key].to_i : 0
|
707
809
|
valid_messages = value.to_i - dropped_messages
|
708
810
|
valid_message_per_tag[key] = valid_messages
|
811
|
+
|
812
|
+
metricsLabels = tag_metrics_set[key]
|
813
|
+
if metricsLabels == nil
|
814
|
+
metricsLabels = MetricsLabels.new
|
815
|
+
end
|
816
|
+
metricsLabels.records_valid = valid_messages
|
817
|
+
# logGroup_metrics_map will have logGroupId as key and metricsLabels_array as value.
|
818
|
+
# In a chunk we can have different logGroupIds but we are creating payloads based on logGroupId and that can internally have different logSourceName and tag data.
|
819
|
+
# Using logGroup_metrics_map, for a given chunk, we can produce the metrics with proper logGroupId and its corresponding values.
|
820
|
+
if metricsLabels.logGroupId != nil
|
821
|
+
if logGroup_metrics_map.has_key?(metricsLabels.logGroupId)
|
822
|
+
metricsLabels_array = logGroup_metrics_map[metricsLabels.logGroupId]
|
823
|
+
else
|
824
|
+
metricsLabels_array = []
|
825
|
+
end
|
826
|
+
metricsLabels_array.push(metricsLabels)
|
827
|
+
logGroup_metrics_map[metricsLabels.logGroupId] = metricsLabels_array
|
828
|
+
end
|
829
|
+
|
830
|
+
@@prometheusMetrics.records_received.set(value.to_i, labels: { tag: key,
|
831
|
+
oci_la_log_group_id: metricsLabels.logGroupId,
|
832
|
+
oci_la_log_source_name: metricsLabels.logSourceName,
|
833
|
+
oci_la_log_set: metricsLabels.logSet})
|
834
|
+
|
835
|
+
@@prometheusMetrics.records_invalid.set(dropped_messages, labels: { tag: key,
|
836
|
+
oci_la_log_group_id: metricsLabels.logGroupId,
|
837
|
+
oci_la_log_source_name: metricsLabels.logSourceName,
|
838
|
+
oci_la_log_set: metricsLabels.logSet,
|
839
|
+
reason: metricsLabels.invalid_reason})
|
840
|
+
@@prometheusMetrics.records_valid.set(valid_messages, labels: { tag: key,
|
841
|
+
oci_la_log_group_id: metricsLabels.logGroupId,
|
842
|
+
oci_la_log_source_name: metricsLabels.logSourceName,
|
843
|
+
oci_la_log_set: metricsLabels.logSet})
|
844
|
+
|
709
845
|
if dropped_messages > 0
|
710
846
|
@@logger.info {"Messages: #{value.to_i} \t Valid: #{valid_messages} \t Invalid: #{dropped_messages} \t tag:#{key}"}
|
711
847
|
end
|
@@ -720,17 +856,27 @@ module Fluent::Plugin
|
|
720
856
|
zippedstream = nil
|
721
857
|
oci_la_log_set = nil
|
722
858
|
logSets_per_logGroupId_map = Hash.new
|
859
|
+
|
860
|
+
metricsLabels_array = logGroup_metrics_map[oci_la_log_group_id]
|
861
|
+
|
723
862
|
# Only MAX_FILES_PER_ZIP (100) files are allowed, which will be grouped and zipped.
|
724
863
|
# Due to MAX_FILES_PER_ZIP constraint, for a oci_la_log_group_id, we can get more than one zip file and those many api calls will be made.
|
725
864
|
logSets_per_logGroupId_map, oci_la_global_metadata = get_logSets_map_per_logGroupId(oci_la_log_group_id,records_per_logGroupId)
|
726
865
|
if logSets_per_logGroupId_map != nil
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
866
|
+
bytes_out = 0
|
867
|
+
records_out = 0
|
868
|
+
chunk_upload_time_taken = nil
|
869
|
+
chunk_upload_time_taken = Benchmark.measure {
|
870
|
+
logSets_per_logGroupId_map.each do |file_count,records_per_logSet_map|
|
871
|
+
zippedstream,number_of_records = get_zipped_stream(oci_la_log_group_id,oci_la_global_metadata,records_per_logSet_map)
|
872
|
+
if zippedstream != nil
|
873
|
+
zippedstream.rewind #reposition buffer pointer to the beginning
|
874
|
+
upload_to_oci(oci_la_log_group_id, number_of_records, zippedstream, metricsLabels_array)
|
875
|
+
end
|
876
|
+
end
|
877
|
+
}.real.round(3)
|
878
|
+
@@prometheusMetrics.chunk_time_to_upload.observe(chunk_upload_time_taken, labels: { oci_la_log_group_id: oci_la_log_group_id})
|
879
|
+
|
734
880
|
end
|
735
881
|
ensure
|
736
882
|
zippedstream&.close
|
@@ -844,8 +990,10 @@ module Fluent::Plugin
|
|
844
990
|
end
|
845
991
|
|
846
992
|
# upload zipped stream to oci
|
847
|
-
def upload_to_oci(oci_la_log_group_id, number_of_records, zippedstream)
|
993
|
+
def upload_to_oci(oci_la_log_group_id, number_of_records, zippedstream, metricsLabels_array)
|
848
994
|
begin
|
995
|
+
error_reason = nil
|
996
|
+
error_code = nil
|
849
997
|
opts = {payload_type: "ZIP"}
|
850
998
|
|
851
999
|
response = @@loganalytics_client.upload_log_events_file(namespace_name=@namespace,
|
@@ -854,6 +1002,19 @@ module Fluent::Plugin
|
|
854
1002
|
opts)
|
855
1003
|
if !response.nil? && response.status == 200 then
|
856
1004
|
headers = response.headers
|
1005
|
+
|
1006
|
+
metricsLabels_array.each { |metricsLabels|
|
1007
|
+
@@prometheusMetrics.records_posted.set(metricsLabels.records_valid, labels: { tag: metricsLabels.tag,
|
1008
|
+
oci_la_log_group_id: metricsLabels.logGroupId,
|
1009
|
+
oci_la_log_source_name: metricsLabels.logSourceName,
|
1010
|
+
oci_la_log_set: metricsLabels.logSet})
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
#zippedstream.rewind #reposition buffer pointer to the beginning
|
1014
|
+
#zipfile = zippedstream&.sysread&.dup
|
1015
|
+
#bytes_out = zipfile&.length
|
1016
|
+
#@@prometheusMetrics.bytes_posted.set(bytes_out, labels: { oci_la_log_group_id: oci_la_log_group_id})
|
1017
|
+
|
857
1018
|
@@logger.info {"The payload has been successfully uploaded to logAnalytics -
|
858
1019
|
oci_la_log_group_id: #{oci_la_log_group_id},
|
859
1020
|
ConsumedRecords: #{number_of_records},
|
@@ -863,13 +1024,16 @@ module Fluent::Plugin
|
|
863
1024
|
opc-object-id: #{headers['opc-object-id']}"}
|
864
1025
|
end
|
865
1026
|
rescue OCI::Errors::ServiceError => serviceError
|
1027
|
+
error_code = serviceError.status_code
|
866
1028
|
case serviceError.status_code
|
867
1029
|
when 400
|
1030
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_400
|
868
1031
|
@@logger.error {"oci upload exception : Error while uploading the payload. Invalid/Incorrect/missing Parameter - opc-request-id:#{serviceError.request_id}"}
|
869
1032
|
if plugin_retry_on_4xx
|
870
1033
|
raise serviceError
|
871
1034
|
end
|
872
1035
|
when 401
|
1036
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_401
|
873
1037
|
@@logger.error {"oci upload exception : Error while uploading the payload. Not Authenticated.
|
874
1038
|
opc-request-id:#{serviceError.request_id}
|
875
1039
|
message: #{serviceError.message}"}
|
@@ -877,6 +1041,7 @@ module Fluent::Plugin
|
|
877
1041
|
raise serviceError
|
878
1042
|
end
|
879
1043
|
when 404
|
1044
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_404
|
880
1045
|
@@logger.error {"oci upload exception : Error while uploading the payload. Authorization failed for given oci_la_log_group_id against given Tenancy Namespace.
|
881
1046
|
oci_la_log_group_id: #{oci_la_log_group_id}
|
882
1047
|
Namespace: #{@namespace}
|
@@ -886,34 +1051,53 @@ module Fluent::Plugin
|
|
886
1051
|
raise serviceError
|
887
1052
|
end
|
888
1053
|
when 429
|
1054
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_429
|
889
1055
|
@@logger.error {"oci upload exception : Error while uploading the payload. Too Many Requests - opc-request-id:#{serviceError.request_id}"}
|
890
1056
|
raise serviceError
|
891
1057
|
when 500
|
1058
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_500
|
892
1059
|
@@logger.error {"oci upload exception : Error while uploading the payload. Internal Server Error - opc-request-id:#{serviceError.request_id}"}
|
893
1060
|
raise serviceError
|
894
1061
|
|
895
1062
|
when 502
|
1063
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_502
|
896
1064
|
@@logger.error {"oci upload exception : Error while uploading the payload. Bad Gateway - opc-request-id:#{serviceError.request_id}"}
|
897
1065
|
raise serviceError
|
898
1066
|
|
899
1067
|
when 503
|
1068
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_503
|
900
1069
|
@@logger.error {"oci upload exception : Error while uploading the payload. Service unavailable - opc-request-id:#{serviceError.request_id}"}
|
901
1070
|
raise serviceError
|
902
1071
|
|
903
1072
|
when 504
|
1073
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_504
|
904
1074
|
@@logger.error {"oci upload exception : Error while uploading the payload. Gateway Timeout - opc-request-id:#{serviceError.request_id}"}
|
905
1075
|
raise serviceError
|
906
1076
|
|
907
1077
|
when 505
|
1078
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_505
|
908
1079
|
@@logger.error {"oci upload exception : Error while uploading the payload. HTTP Version Not Supported - opc-request-id:#{serviceError.request_id}"}
|
909
1080
|
raise serviceError
|
910
1081
|
else
|
1082
|
+
error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_UNKNOWN
|
911
1083
|
@@logger.error {"oci upload exception : Error while uploading the payload #{serviceError.message}"}
|
912
1084
|
raise serviceError
|
913
1085
|
end
|
914
1086
|
rescue => ex
|
1087
|
+
error_reason = ex
|
915
1088
|
@@logger.error {"oci upload exception : Error while uploading the payload. #{ex}"}
|
1089
|
+
ensure
|
1090
|
+
if error_reason != nil
|
1091
|
+
metricsLabels_array.each { |metricsLabels|
|
1092
|
+
@@prometheusMetrics.records_error.set(metricsLabels.records_valid, labels: { tag: metricsLabels.tag,
|
1093
|
+
oci_la_log_group_id: metricsLabels.logGroupId,
|
1094
|
+
oci_la_log_source_name: metricsLabels.logSourceName,
|
1095
|
+
oci_la_log_set: metricsLabels.logSet,
|
1096
|
+
error_code: error_code,
|
1097
|
+
reason: error_reason})
|
1098
|
+
}
|
1099
|
+
end
|
916
1100
|
end
|
917
1101
|
end
|
918
1102
|
end
|
919
|
-
end
|
1103
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-oci-logging-analytics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Oracle
|
8
|
+
- 'OCI Observability: Logging Analytics'
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2022-
|
12
|
+
date: 2022-06-20 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rake
|
@@ -78,17 +79,32 @@ dependencies:
|
|
78
79
|
requirements:
|
79
80
|
- - "~>"
|
80
81
|
- !ruby/object:Gem::Version
|
81
|
-
version: '2.
|
82
|
+
version: '2.16'
|
82
83
|
type: :runtime
|
83
84
|
prerelease: false
|
84
85
|
version_requirements: !ruby/object:Gem::Requirement
|
85
86
|
requirements:
|
86
87
|
- - "~>"
|
87
88
|
- !ruby/object:Gem::Version
|
88
|
-
version: '2.
|
89
|
-
|
89
|
+
version: '2.16'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: prometheus-client
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 4.0.0
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.0.0
|
104
|
+
description: OCI Logging Analytics Fluentd output plugin for ingesting the collected
|
105
|
+
log events to OCI Logging Analytics.
|
90
106
|
email:
|
91
|
-
-
|
107
|
+
- oci_la_plugins_grp@oracle.com
|
92
108
|
executables: []
|
93
109
|
extensions: []
|
94
110
|
extra_rdoc_files: []
|
@@ -101,7 +117,10 @@ files:
|
|
101
117
|
homepage:
|
102
118
|
licenses:
|
103
119
|
- UPL-1.0
|
104
|
-
metadata:
|
120
|
+
metadata:
|
121
|
+
documentation_uri: https://docs.oracle.com/en/learn/oci_logging_analytics_fluentd/
|
122
|
+
source_code_uri: https://github.com/oracle-quickstart/oci-logan-fluentd-output-plugin
|
123
|
+
changelog_uri: https://github.com/oracle-quickstart/oci-logan-fluentd-output-plugin/blob/main/CHANGELOG.md
|
105
124
|
post_install_message:
|
106
125
|
rdoc_options: []
|
107
126
|
require_paths:
|
@@ -110,15 +129,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
129
|
requirements:
|
111
130
|
- - ">="
|
112
131
|
- !ruby/object:Gem::Version
|
113
|
-
version:
|
132
|
+
version: 2.6.0
|
114
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
134
|
requirements:
|
116
135
|
- - ">="
|
117
136
|
- !ruby/object:Gem::Version
|
118
137
|
version: '0'
|
119
138
|
requirements: []
|
120
|
-
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.6.13
|
121
141
|
signing_key:
|
122
142
|
specification_version: 4
|
123
|
-
summary: Fluentd
|
143
|
+
summary: Fluentd output plugin for OCI Logging Analytics.
|
124
144
|
test_files: []
|