fluent-plugin-oci-logging-analytics 2.0.2 → 2.0.3

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: 370ab2ca02c76665077069c52e02b97297b238a990bd0ba9475f86e588fb76c5
4
- data.tar.gz: 0a0428639be123f7f908132d2965d6ceabb15054ea080e239b6da3e19b4ad7a6
3
+ metadata.gz: 6a06f05f13c8058d4e2a6f3a6d4b8cf065f3c558d27f9fecf43ecbabdbb2f1f1
4
+ data.tar.gz: 076c4ea4b27fbf7230c237596162ca75d7e17450112f67aee848ffea52828123
5
5
  SHA512:
6
- metadata.gz: 8062761ad58799206282392787e6fe9440bb58f1b29a2ac692b6212e08fedc7cb6fd9c4b3b992fe56e8e02d6bc211defe92a51fb04f5a50ea49581d004eb10b6
7
- data.tar.gz: ddbdfe55b2ee221112e6accdfb113bfda2a585d624efc6f5489ddc0953816784d1dad9d126f34b011ce93494a1b112f9ee24d42d58d80dbfab559efa6f07b6c1
6
+ metadata.gz: 17a4f913bdb5c7ec6bf9bf8f812efb8f1da9f2e55180c25806a49d5782ffcfac21080eda04a036a89189aa8d33d95bf8947ec34ac9a7d508fd190077efa6bd09
7
+ data.tar.gz: 6c7dbb1934d8850527fefd7163e993034cf681b239d08041cc9b0085439b6e8b92ba9b4142ec03e5653a3e0d63fc2711b75b0fac9ef78d60d0694f5a0719abd6
@@ -0,0 +1,13 @@
1
+ class MetricsLabels
2
+ attr_accessor :tag, :logGroupId, :logSourceName, :logSet, :invalid_reason, :records_valid, :records_per_tag, :latency
3
+ def initialize
4
+ @tag = nil
5
+ @logGroupId = nil
6
+ @logSourceName = nil
7
+ @logSet = nil
8
+ @invalid_reason = nil
9
+ @records_valid = 0
10
+ @records_per_tag = 0
11
+ @latency = 0
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ require 'prometheus/client'
2
+ require 'prometheus/client/registry'
3
+ require 'prometheus/client/gauge'
4
+ require 'prometheus/client/histogram'
5
+ require 'singleton'
6
+
7
+ class PrometheusMetrics
8
+ include Singleton
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
+ def initialize
12
+ createMetrics
13
+ registerMetrics
14
+ end
15
+ def createMetrics
16
+ gauge = Prometheus::Client::Gauge
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
+ histogram = Prometheus::Client::Histogram
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
+ end
28
+
29
+ def registerMetrics
30
+ registry = Prometheus::Client.registry
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
+ end
41
+ end
@@ -8,6 +8,8 @@ require 'zip'
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'
11
13
 
12
14
  # Import only specific OCI modules to improve load times and reduce the memory requirements.
13
15
  require 'oci/auth/auth'
@@ -53,8 +55,25 @@ module Fluent::Plugin
53
55
  helpers :thread, :event_emitter
54
56
 
55
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
+
56
74
  @@logger = nil
57
75
  @@loganalytics_client = nil
76
+ @@prometheusMetrics = nil
58
77
  @@logger_config_errors = []
59
78
 
60
79
 
@@ -252,6 +271,7 @@ module Fluent::Plugin
252
271
 
253
272
  def configure(conf)
254
273
  super
274
+ @@prometheusMetrics = PrometheusMetrics.instance
255
275
  initialize_logger
256
276
 
257
277
  initialize_loganalytics_client
@@ -504,32 +524,36 @@ module Fluent::Plugin
504
524
 
505
525
  def is_valid_record(record_hash,record)
506
526
  begin
527
+ invalid_reason = nil
507
528
  if !record_hash.has_key?("message")
529
+ invalid_reason = OutOracleOCILogAnalytics::METRICS_INVALID_REASON_MESSAGE
508
530
  if record_hash.has_key?("tag")
509
531
  @@logger.warn {"Invalid records associated with tag : #{record["tag"]}. 'message' field is not present in the record."}
510
532
  else
511
533
  @@logger.info {"InvalidRecord: #{record}"}
512
534
  @@logger.warn {"Invalid record. 'message' field is not present in the record."}
513
535
  end
514
- return false
536
+ return false,invalid_reason
515
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
516
539
  if record_hash.has_key?("tag")
517
540
  @@logger.warn {"Invalid records associated with tag : #{record["tag"]}.'oci_la_log_group_id' must not be empty.
518
541
  Skipping all the records associated with the tag"}
519
542
  else
520
543
  @@logger.warn {"Invalid record.'oci_la_log_group_id' must not be empty"}
521
544
  end
522
- return false
545
+ return false,invalid_reason
523
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
524
548
  if record_hash.has_key?("tag")
525
549
  @@logger.warn {"Invalid records associated with tag : #{record["tag"]}.'oci_la_log_source_name' must not be empty.
526
550
  Skipping all the records associated with the tag"}
527
551
  else
528
552
  @@logger.warn {"Invalid record.'oci_la_log_source_name' must not be empty"}
529
553
  end
530
- return false
554
+ return false,invalid_reason
531
555
  else
532
- return true
556
+ return true,invalid_reason
533
557
  end
534
558
  end
535
559
  end
@@ -580,6 +604,11 @@ module Fluent::Plugin
580
604
  current_f, current_s = current.to_f, current.strftime("%Y%m%dT%H%M%S%9NZ")
581
605
  records = []
582
606
  count = 0
607
+ latency = 0
608
+ records_per_tag = 0
609
+
610
+ tag_metrics_set = Hash.new
611
+ logGroup_labels_set = Hash.new
583
612
 
584
613
  invalid_tag_set = Set.new
585
614
  incoming_records_per_tag = Hash.new
@@ -587,130 +616,166 @@ module Fluent::Plugin
587
616
  tags_per_logGroupId = Hash.new
588
617
  tag_logSet_map = Hash.new
589
618
  tag_metadata_map = Hash.new
619
+ incoming_records = 0
590
620
 
591
621
  chunk.each do |time, record|
592
-
622
+ incoming_records += 1
623
+ metricsLabels = MetricsLabels.new
593
624
  if !record.nil?
594
- record_hash = record.keys.map {|x| [x,true]}.to_h
595
- is_tag_exists = false
596
- if record_hash.has_key?("tag") && is_valid(record["tag"])
597
- is_tag_exists = true
598
- end
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
599
632
 
600
- if is_tag_exists && incoming_records_per_tag.has_key?(record["tag"])
601
- incoming_records_per_tag[record["tag"]] += 1
602
- elsif is_tag_exists
603
- incoming_records_per_tag[record["tag"]] = 1
604
- end
605
- #For any given tag, if one record fails (mandatory fields validation) then all the records from that source will be ignored
606
- if is_tag_exists && invalid_tag_set.include?(record["tag"])
607
- invalid_records_per_tag[record["tag"]] += 1
608
- next #This tag is already present in the invalid_tag_set, so ignoring the message.
609
- end
610
- #Setting tag/default value for oci_la_log_path, when not provided in config file.
611
- if !record_hash.has_key?("oci_la_log_path") || !is_valid(record["oci_la_log_path"])
612
- if is_tag_exists
613
- record["oci_la_log_path"] = record["tag"]
614
- else
615
- 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
616
637
  end
617
- end
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
618
651
 
619
- #Extracting oci_la_log_set when oci_la_log_set_key and oci_la_log_set_ext_regex is provided.
620
- #1) oci_la_log_set param is not provided in config file and above logic not executed.
621
- #2) Valid oci_la_log_set_key + No oci_la_log_set_ext_regex
622
- #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
623
- #b) No Valid key available in record with oci_la_log_set_key corresponding value --> nil
624
- #3) Valid key available in record with oci_la_log_set_key corresponding value + Valid oci_la_log_set_ext_regex
625
- #a) Parse success --> parsed oci_la_log_set
626
- #b) Parse failure --> nil (as oci_la_log_set value)
627
- #4) No oci_la_log_set_key --> do nothing --> nil
628
-
629
- #Extracting oci_la_log_set when oci_la_log_set and oci_la_log_set_ext_regex is provided.
630
- #1) Valid oci_la_log_set + No oci_la_log_set_ext_regex --> oci_la_log_set
631
- #2) Valid oci_la_log_set + Valid oci_la_log_set_ext_regex
632
- #a) Parse success --> parsed oci_la_log_set
633
- #b) Parse failure --> nil (as oci_la_log_set value)
634
- #3) No oci_la_log_set --> do nothing --> nil
635
-
636
- unparsed_logSet = nil
637
- processed_logSet = nil
638
- if is_tag_exists && tag_logSet_map.has_key?(record["tag"])
639
- record["oci_la_log_set"] = tag_logSet_map[record["tag"]]
640
- else
641
- if record_hash.has_key?("oci_la_log_set_key")
642
- if is_valid(record["oci_la_log_set_key"]) && record_hash.has_key?(record["oci_la_log_set_key"])
643
- if is_valid(record[record["oci_la_log_set_key"]])
644
- unparsed_logSet = record[record["oci_la_log_set_key"]]
645
- processed_logSet = get_or_parse_logSet(unparsed_logSet,record, record_hash,is_tag_exists)
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
646
680
  end
647
681
  end
648
- end
649
- if !is_valid(processed_logSet) && record_hash.has_key?("oci_la_log_set")
650
- if is_valid(record["oci_la_log_set"])
651
- unparsed_logSet = record["oci_la_log_set"]
652
- processed_logSet = get_or_parse_logSet(unparsed_logSet,record, record_hash,is_tag_exists)
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
653
687
  end
654
- end
655
- record["oci_la_log_set"] = processed_logSet
656
- tag_logSet_map[record["tag"]] = processed_logSet
657
- end
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)
658
692
 
659
- unless is_valid_record(record_hash,record)
660
- if is_tag_exists
661
- invalid_tag_set.add(record["tag"])
662
- invalid_records_per_tag[record["tag"]] = 1
663
- end
664
- next
665
- end
666
- #This will check for null or empty messages and only that record will be ignored.
667
- if !is_valid(record["message"])
668
- if is_tag_exists
669
- @@logger.warn {"'message' field has empty value, Skipping records associated with tag : #{record["tag"]}."}
670
- if invalid_records_per_tag.has_key?(record["tag"])
671
- invalid_records_per_tag[record["tag"]] += 1
672
- else
693
+ unless is_valid
694
+ if is_tag_exists
695
+ invalid_tag_set.add(record["tag"])
673
696
  invalid_records_per_tag[record["tag"]] = 1
674
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
675
719
  else
676
- @@logger.warn {"'message' field has empty value, Skipping record."}
720
+ record["message"] = json_message_handler(record["message"])
677
721
  end
678
- next
679
- else
680
- record["message"] = json_message_handler(record["message"])
681
- end
682
722
 
683
- if record_hash.has_key?("kubernetes")
684
- record["oci_la_metadata"] = get_kubernetes_metadata(record["oci_la_metadata"],record)
685
- end
723
+ if record_hash.has_key?("kubernetes")
724
+ record["oci_la_metadata"] = get_kubernetes_metadata(record["oci_la_metadata"],record)
725
+ end
686
726
 
687
- if tag_metadata_map.has_key?(record["tag"])
688
- record["oci_la_metadata"] = tag_metadata_map[record["tag"]]
689
- else
690
- if record_hash.has_key?("oci_la_metadata")
691
- record["oci_la_metadata"] = get_valid_metadata(record["oci_la_metadata"])
692
- tags_per_logGroupId[record["tag"]] = record["oci_la_metadata"]
693
- else
694
- tags_per_logGroupId[record["tag"]] = nil
695
- end
696
- end
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
697
737
 
698
- if is_tag_exists
699
- if tags_per_logGroupId.has_key?(record["oci_la_log_group_id"])
700
- if !tags_per_logGroupId[record["oci_la_log_group_id"]].include?(record["tag"])
701
- tags_per_logGroupId[record["oci_la_log_group_id"]] += ", "+record["tag"]
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
702
746
  end
703
- else
704
- tags_per_logGroupId[record["oci_la_log_group_id"]] = record["tag"]
705
- end
706
- end
707
747
 
708
- records << record
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
709
768
  else
710
769
  @@logger.trace {"Record is nil, ignoring the record"}
711
770
  end
712
771
  end
713
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
+
714
779
  lrpes_for_logGroupId = {}
715
780
  records.group_by{|record|
716
781
  oci_la_log_group_id = record['oci_la_log_group_id']
@@ -721,29 +786,62 @@ module Fluent::Plugin
721
786
  rescue => ex
722
787
  @@logger.error {"Error occurred while grouping records by oci_la_log_group_id:#{ex.inspect}"}
723
788
  end
724
- 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
725
790
  end
726
791
  # main entry point for FluentD's flush_threads, which get invoked
727
792
  # when a chunk is ready for flushing (see chunk limits and flush_intervals)
728
793
  def write(chunk)
729
794
  @@logger.info {"Received new chunk, started processing ..."}
730
- metrics = Hash.new
731
- metrics["count"] = 0
732
- metrics["event"] = "zipping"
733
- metrics["bytes_in"] = chunk.bytesize
734
- metrics['records_dropped'] = 0
795
+ #@@prometheusMetrics.bytes_received.set(chunk.bytesize, labels: { tag: nil})
735
796
  begin
736
797
  # 1) Create an in-memory zipfile for the given FluentD chunk
737
798
  # 2) Synchronization has been removed. See EMCLAS-28675
738
799
 
739
800
  begin
740
801
  lrpes_for_logGroupId = {}
741
- 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)
742
803
  valid_message_per_tag = Hash.new
804
+ logGroup_metrics_map = Hash.new
805
+ metricsLabels_array = []
806
+
743
807
  incoming_records_per_tag.each do |key,value|
744
808
  dropped_messages = (invalid_records_per_tag.has_key?(key)) ? invalid_records_per_tag[key].to_i : 0
745
809
  valid_messages = value.to_i - dropped_messages
746
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
+
747
845
  if dropped_messages > 0
748
846
  @@logger.info {"Messages: #{value.to_i} \t Valid: #{valid_messages} \t Invalid: #{dropped_messages} \t tag:#{key}"}
749
847
  end
@@ -758,17 +856,27 @@ module Fluent::Plugin
758
856
  zippedstream = nil
759
857
  oci_la_log_set = nil
760
858
  logSets_per_logGroupId_map = Hash.new
859
+
860
+ metricsLabels_array = logGroup_metrics_map[oci_la_log_group_id]
861
+
761
862
  # Only MAX_FILES_PER_ZIP (100) files are allowed, which will be grouped and zipped.
762
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.
763
864
  logSets_per_logGroupId_map, oci_la_global_metadata = get_logSets_map_per_logGroupId(oci_la_log_group_id,records_per_logGroupId)
764
865
  if logSets_per_logGroupId_map != nil
765
- logSets_per_logGroupId_map.each do |file_count,records_per_logSet_map|
766
- zippedstream,number_of_records = get_zipped_stream(oci_la_log_group_id,oci_la_global_metadata,records_per_logSet_map)
767
- if zippedstream != nil
768
- zippedstream.rewind #reposition buffer pointer to the beginning
769
- upload_to_oci(oci_la_log_group_id, number_of_records, zippedstream)
770
- end
771
- end
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
+
772
880
  end
773
881
  ensure
774
882
  zippedstream&.close
@@ -882,8 +990,10 @@ module Fluent::Plugin
882
990
  end
883
991
 
884
992
  # upload zipped stream to oci
885
- 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)
886
994
  begin
995
+ error_reason = nil
996
+ error_code = nil
887
997
  opts = {payload_type: "ZIP"}
888
998
 
889
999
  response = @@loganalytics_client.upload_log_events_file(namespace_name=@namespace,
@@ -892,6 +1002,19 @@ module Fluent::Plugin
892
1002
  opts)
893
1003
  if !response.nil? && response.status == 200 then
894
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
+
895
1018
  @@logger.info {"The payload has been successfully uploaded to logAnalytics -
896
1019
  oci_la_log_group_id: #{oci_la_log_group_id},
897
1020
  ConsumedRecords: #{number_of_records},
@@ -901,13 +1024,16 @@ module Fluent::Plugin
901
1024
  opc-object-id: #{headers['opc-object-id']}"}
902
1025
  end
903
1026
  rescue OCI::Errors::ServiceError => serviceError
1027
+ error_code = serviceError.status_code
904
1028
  case serviceError.status_code
905
1029
  when 400
1030
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_400
906
1031
  @@logger.error {"oci upload exception : Error while uploading the payload. Invalid/Incorrect/missing Parameter - opc-request-id:#{serviceError.request_id}"}
907
1032
  if plugin_retry_on_4xx
908
1033
  raise serviceError
909
1034
  end
910
1035
  when 401
1036
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_401
911
1037
  @@logger.error {"oci upload exception : Error while uploading the payload. Not Authenticated.
912
1038
  opc-request-id:#{serviceError.request_id}
913
1039
  message: #{serviceError.message}"}
@@ -915,6 +1041,7 @@ module Fluent::Plugin
915
1041
  raise serviceError
916
1042
  end
917
1043
  when 404
1044
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_404
918
1045
  @@logger.error {"oci upload exception : Error while uploading the payload. Authorization failed for given oci_la_log_group_id against given Tenancy Namespace.
919
1046
  oci_la_log_group_id: #{oci_la_log_group_id}
920
1047
  Namespace: #{@namespace}
@@ -924,33 +1051,52 @@ module Fluent::Plugin
924
1051
  raise serviceError
925
1052
  end
926
1053
  when 429
1054
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_429
927
1055
  @@logger.error {"oci upload exception : Error while uploading the payload. Too Many Requests - opc-request-id:#{serviceError.request_id}"}
928
1056
  raise serviceError
929
1057
  when 500
1058
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_500
930
1059
  @@logger.error {"oci upload exception : Error while uploading the payload. Internal Server Error - opc-request-id:#{serviceError.request_id}"}
931
1060
  raise serviceError
932
1061
 
933
1062
  when 502
1063
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_502
934
1064
  @@logger.error {"oci upload exception : Error while uploading the payload. Bad Gateway - opc-request-id:#{serviceError.request_id}"}
935
1065
  raise serviceError
936
1066
 
937
1067
  when 503
1068
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_503
938
1069
  @@logger.error {"oci upload exception : Error while uploading the payload. Service unavailable - opc-request-id:#{serviceError.request_id}"}
939
1070
  raise serviceError
940
1071
 
941
1072
  when 504
1073
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_504
942
1074
  @@logger.error {"oci upload exception : Error while uploading the payload. Gateway Timeout - opc-request-id:#{serviceError.request_id}"}
943
1075
  raise serviceError
944
1076
 
945
1077
  when 505
1078
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_505
946
1079
  @@logger.error {"oci upload exception : Error while uploading the payload. HTTP Version Not Supported - opc-request-id:#{serviceError.request_id}"}
947
1080
  raise serviceError
948
1081
  else
1082
+ error_reason = OutOracleOCILogAnalytics::METRICS_SERVICE_ERROR_REASON_UNKNOWN
949
1083
  @@logger.error {"oci upload exception : Error while uploading the payload #{serviceError.message}"}
950
1084
  raise serviceError
951
1085
  end
952
1086
  rescue => ex
1087
+ error_reason = ex
953
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
954
1100
  end
955
1101
  end
956
1102
  end
metadata CHANGED
@@ -1,7 +1,7 @@
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.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oracle
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-02-17 00:00:00.000000000 Z
12
+ date: 2022-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -79,14 +79,28 @@ dependencies:
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.13'
82
+ version: '2.16'
83
83
  type: :runtime
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '2.13'
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: 2.1.0
97
+ type: :runtime
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 2.1.0
90
104
  description: OCI Logging Analytics Fluentd output plugin for ingesting the collected
91
105
  log events to OCI Logging Analytics.
92
106
  email:
@@ -97,6 +111,8 @@ extra_rdoc_files: []
97
111
  files:
98
112
  - lib/fluent/dto/logEvents.rb
99
113
  - lib/fluent/dto/logEventsJson.rb
114
+ - lib/fluent/metrics/metricsLabels.rb
115
+ - lib/fluent/metrics/prometheusMetrics.rb
100
116
  - lib/fluent/plugin/out_oci-logging-analytics.rb
101
117
  homepage:
102
118
  licenses: