protor 0.0.11 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 08f75ca473acd6b2205bd2bd6eeee6436d8ee131
4
- data.tar.gz: 3e4902b2fe77f54832bcb9004b77886784b89eeb
3
+ metadata.gz: 792b0db1c9b32cc19645c2c08afc39a5446b5834
4
+ data.tar.gz: f2cdf2b5eba5ec663611a0718f4c6c7fc5d7732c
5
5
  SHA512:
6
- metadata.gz: 56d4a7e9dfff42ea32ec8449372c8a583bfeb0187a150d949caa59781e2b0cd9d7c3c643e6706db8e63c33a914152cb28d7a630f35eeff679d070be3ce138f78
7
- data.tar.gz: c47557219550a752434337d210dd5a1396fd51bee68f6bb14ba54cf3a97ac39abe17cff18cc7e3af41416c9deb169f2ecd771da4af0b998aecdb8a5a10c8fcd4
6
+ metadata.gz: d551325d26dc6e8f62bd6670feb85ac1f66ef49a3a917113d014612da99770197da1f5bf6d5a6890ba046f7ec675771d3c38da50408c8d4822e6fadb769a8190
7
+ data.tar.gz: fd9e321c2650a27e2b8b343972157a9f1e5dabdac4f3c32e4d04f9db3dd80c9830e9c7bdf12289d4de1643ea59191d4fd9920cacba98b7dfcf149b7dce4f08f1
data/README.md CHANGED
@@ -16,36 +16,39 @@ bundle install
16
16
  It automatically aggregate value
17
17
 
18
18
  ````ruby
19
- Protor.counter(:counter, 1, {label1: 1}) # value => 1
20
- Protor.counter(:counter, 1, {label1: 1}) # value => 2
19
+ protor.counter(:counter, 1, {label1: 1}) # value => 1
20
+ protor.counter(:counter, 1, {label1: 1}) # value => 2
21
21
  ````
22
22
  ### Gauge
23
23
  It automatically replace value
24
24
  ````ruby
25
- Protor.gauge(:gauge, 50) # value 50
26
- Protor.gauge(:gauge, 20) # value 20
25
+ protor.gauge(:gauge, 50) # value 50
26
+ protor.gauge(:gauge, 20) # value 20
27
27
  ````
28
28
 
29
29
  ### Histogram
30
30
  It save all observed values
31
31
  ````ruby
32
- Protor.histogram(:histogram, 10, {label1: 1}, [1,2,3,4]) # observed value [10]
33
- Protor.histogram(:histogram, 2, {label1: 1}, [1,2,3,4]( # observed value [10,2]
32
+ protor.histogram(:histogram, 10, {label1: 1}, [1,2,3,4]) # observed value [10]
33
+ protor.histogram(:histogram, 2, {label1: 1}, [1,2,3,4]( # observed value [10,2]
34
34
  ````
35
35
 
36
36
  ### Publish
37
37
  To publish all saved metrics to aggregator
38
38
  ````ruby
39
- Protor.publish
39
+ protor.publish
40
40
  ````
41
41
 
42
42
  ## Configuration
43
43
  To configure protor:
44
44
  ````ruby
45
- Protor.configure do |config|
46
- config.host = 'localhost' # aggregator host, default to localhost
47
- config.port = 10601 # aggregator port, default to 10601
48
- config.max_packet_size = 56607 # max udp packet buffer, default to 56607
45
+ $protor = Protor.new do |conf|
46
+ conf[:client] = :udp # valid option :udp and :logger, use :logger to print into a Logger
47
+ conf[:host] = 'localhost' # prometheus_aggregator host
48
+ conf[:port] = 10601 # prometheus_aggregator port
49
+ conf[:logger] = Rails.logger # logger to be used by protor
50
+ conf[:packet_size] = 56_607 # max udp packet buffer
51
+ conf[:formatter] = :udp # valid option only :udp, format to send
49
52
  end
50
53
  ````
51
54
 
@@ -1,50 +1,73 @@
1
1
  require 'monitor'
2
2
 
3
- require_relative 'protor/error'
4
- require_relative 'protor/configuration'
5
- require_relative 'protor/client'
3
+ require_relative 'protor/udp_formatter'
4
+ require_relative 'protor/udp_client'
5
+ require_relative 'protor/logger_client'
6
6
  require_relative 'protor/registry'
7
7
  require_relative 'protor/version'
8
8
 
9
- module Protor
10
- extend MonitorMixin
11
- end
9
+ class Protor
10
+ include MonitorMixin
12
11
 
13
- class << Protor
14
- def configuration
15
- @configuration ||= Protor::Configuration.new
16
- end
12
+ DEFAULT_CONFIG = {
13
+ client: :udp,
14
+ formatter: :udp,
15
+ host: 'localhost',
16
+ port: 10601,
17
+ packet_size: 56_607
18
+ }
19
+
20
+ attr_reader :config, :registry
17
21
 
18
- def configure
19
- yield(configuration)
22
+ def initialize(&block)
23
+ super(&block)
24
+
25
+ @config = DEFAULT_CONFIG.dup
26
+ @registry = Registry.new
27
+ yield(config) if block_given?
20
28
  end
21
29
 
22
30
  def publish
23
- synchronize do
24
- unless registry.empty?
25
- client.publish(registry)
26
- reset
27
- end
28
- end
31
+ safely{ client.publish(registry) }
32
+ logger.debug("publish") if logger
29
33
  end
30
34
 
31
35
  [:counter, :gauge, :histogram].each do |method|
32
- define_method method do |*args, &block|
33
- synchronize{ registry.public_send(method, *args, &block) }
36
+ define_method method do |*args|
37
+ safely{ registry.public_send(method, *args) }
38
+ logger.debug("#{method} #{args}") if logger
34
39
  end
35
40
  end
36
41
 
37
42
  private
38
43
 
44
+ def safely(&block)
45
+ synchronize(&block)
46
+ rescue StandardError => err
47
+ logger.error(err) if logger
48
+ raise err unless silent
49
+ end
50
+
39
51
  def client
40
- @client ||= Protor::Client.new(configuration)
52
+ @client ||=
53
+ case config[:client]
54
+ when :udp; UDPClient.new(config[:host], config[:port], formatter)
55
+ when :logger; LoggerClient.new(logger, formatter)
56
+ end
57
+ end
58
+
59
+ def formatter
60
+ @formatter ||=
61
+ case config[:formatter]
62
+ when :udp; UDPFormatter.new(config[:packet_size])
63
+ end
41
64
  end
42
65
 
43
- def registry
44
- @registry || reset
66
+ def logger
67
+ config[:logger]
45
68
  end
46
69
 
47
- def reset
48
- @registry = Protor::Registry.new(configuration)
70
+ def silent
71
+ config[:silent]
49
72
  end
50
73
  end
@@ -0,0 +1,66 @@
1
+ class Protor
2
+ class Entry
3
+ attr_reader :name, :type, :value, :labels, :additional
4
+ attr_writer :value
5
+
6
+ VALID_NAME = /^[a-zA-Z_:][a-zA-Z0-9_:]+$/
7
+ VALID_TYPE = [:c, :g, :h]
8
+ VALID_LABEL_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/
9
+ VALID_LABEL_VALUE = /^[^;|=]+$/
10
+
11
+ def initialize(name, type, value, labels = nil, additional = nil)
12
+ @name = name.to_s
13
+ @type = type
14
+ @value = value
15
+ @labels = labels || {}
16
+ @additional = additional || []
17
+
18
+ verify
19
+ end
20
+
21
+ private
22
+
23
+ def verify
24
+ raise InvalidNameError, name unless name =~ VALID_NAME
25
+ raise InvalidTypeError, type unless VALID_TYPE.include?(type)
26
+ labels.each do |k, v|
27
+ raise InvalidLabelNameError, labels unless k =~ VALID_LABEL_NAME
28
+ raise InvalidLabelValueError, labels unless v =~ VALID_LABEL_VALUE
29
+ end
30
+ additional.each do |a|
31
+ raise InvalidAdditionalError, additional unless a.is_a?(Numeric)
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ class InvalidNameError < StandardError
38
+ def initialize(message)
39
+ super("Invalid name #{message}, please satisfy /^[a-zA-Z_:][a-zA-Z0-9_:]+$/")
40
+ end
41
+ end
42
+
43
+ class InvalidTypeError < StandardError
44
+ def initialize(message)
45
+ super("Invalid type #{message}, allowed types are [c, g, h]")
46
+ end
47
+ end
48
+
49
+ class InvalidLabelNameError < StandardError
50
+ def initialize(message)
51
+ super("Invalid label name #{message}, please satisfy /^[a-zA-Z_][a-zA-Z0-9_]*$/")
52
+ end
53
+ end
54
+
55
+ class InvalidLabelValueError < StandardError
56
+ def initialize(message)
57
+ super("Invalid label value #{message}, please satisfy /^[^;|=\s]+$/")
58
+ end
59
+ end
60
+
61
+ class InvalidAdditionalError < StandardError
62
+ def initialize(message)
63
+ super("Invalid additional {message}, additional must be numbers")
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ class Protor
2
+ class EntryFamily
3
+ attr_reader :name, :type, :data
4
+
5
+ def initialize(name, type)
6
+ @name = name
7
+ @type = type
8
+ @data = {}
9
+ end
10
+
11
+ def []=(label, value)
12
+ data[label] = value
13
+ end
14
+
15
+ def [](label)
16
+ data[label]
17
+ end
18
+
19
+ def each
20
+ return unless block_given?
21
+
22
+ data.each_value{ |d| yield(d) }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ class Protor
2
+ class LoggerClient
3
+ attr_reader :logger, :formatter
4
+
5
+ def initialize(logger, formatter)
6
+ @logger = logger
7
+ @formatter = formatter
8
+ end
9
+
10
+ def publish(payload)
11
+ formatter.format(payload) do |msg|
12
+ logger.info(msg)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,70 +1,84 @@
1
- require_relative 'payload'
2
- require_relative 'accumulator'
3
- require_relative 'observer'
1
+ require_relative 'entry'
2
+ require_relative 'entry_family'
4
3
 
5
- module Protor
4
+ class Protor
6
5
  class Registry
7
- HistogramDefaultBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].freeze
6
+ attr_reader :families
8
7
 
9
- def initialize(options)
10
- @options = options
8
+ DEFAULT_BUCKET = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].freeze
9
+
10
+ def initialize
11
+ @families = {}
11
12
  end
12
13
 
13
14
  def counter(metric_name, value, labels = {})
14
- verify_label(labels)
15
- counter_data.inc(metric_name, value, labels)
15
+ labels = stringify(labels)
16
+ fam = family(metric_name, :counter)
17
+
18
+ if (entry = fam[labels])
19
+ entry.value += value
20
+ else
21
+ fam[labels] = Entry.new(metric_name, :c, value, labels)
22
+ end
16
23
  end
17
24
 
18
25
  def gauge(metric_name, value, labels = {})
19
- verify_label(labels)
20
- gauge_data.set(metric_name, value, labels)
26
+ labels = stringify(labels)
27
+ fam = family(metric_name, :gauge)
28
+
29
+ if (entry = fam[labels])
30
+ entry.value = value
31
+ else
32
+ fam[labels] = Entry.new(metric_name, :g, value, labels)
33
+ end
21
34
  end
22
35
 
23
- def histogram(metric_name, value, labels = {}, buckets = HistogramDefaultBuckets)
24
- verify_label(labels)
25
- histogram_data.observe(metric_name, value, labels, buckets)
36
+ def histogram(metric_name, value, labels = {}, buckets = DEFAULT_BUCKET)
37
+ labels = stringify(labels)
38
+ fam = family(metric_name, :histogram)
39
+
40
+ entry = Entry.new(metric_name, :h, value, labels, buckets)
41
+ if (array = fam[labels])
42
+ array << entry
43
+ else
44
+ fam[labels] = [ entry ]
45
+ end
26
46
  end
27
47
 
28
48
  def each
29
- payload = Payload.new options.max_packet_size
30
- all_data.each do |data|
31
- unless payload.add(data)
32
- yield payload.to_s
33
-
34
- payload = Payload.new options.max_packet_size
35
- payload.add(data)
49
+ families.each_value do |family|
50
+ if family.type == :histogram
51
+ family.each{ |arr| arr.each{ |e| yield(e) }}
52
+ else
53
+ family.each{ |e| yield(e) }
36
54
  end
37
55
  end
38
-
39
- yield payload.to_s
40
56
  end
41
57
 
42
58
  def empty?
43
- [@counter, @gauge, @histogram].all?{ |metrics| metrics && metrics.empty? }
59
+ families.empty?
44
60
  end
45
61
 
46
62
  private
47
63
 
48
- attr_reader :options
49
-
50
- def verify_label(label)
51
- raise LabelError.new("Need Hash as labels, but found #{label.class.name}") if label && !label.is_a?(Hash)
52
- end
53
-
54
- def counter_data
55
- @counter ||= Accumulator.new(:counter)
64
+ def stringify(labels)
65
+ {}.tap do |h|
66
+ labels.each{ |k, v| h[k.to_s] = v.to_s }
67
+ end
56
68
  end
57
69
 
58
- def gauge_data
59
- @gauge ||= Accumulator.new(:gauge)
60
- end
70
+ def family(name, type)
71
+ families[name] ||= EntryFamily.new(name, type)
72
+ family = families[name]
73
+ raise IncompatibleTypeError.new(name, family.type, type) if family.type != type
61
74
 
62
- def histogram_data
63
- @histogram ||= Observer.new(:histogram)
75
+ return family
64
76
  end
77
+ end
65
78
 
66
- def all_data
67
- [counter_data.to_a, gauge_data.to_a, histogram_data.to_a].flatten
79
+ class IncompatibleTypeError < StandardError
80
+ def initialize(name, previous, now)
81
+ super("Incompatible type for metric #{name}, previously it was a #{previous}, now it is a #{now}")
68
82
  end
69
83
  end
70
84
  end
@@ -0,0 +1,31 @@
1
+ require 'socket'
2
+
3
+ class Protor
4
+ class UDPClient
5
+ attr_reader :host, :port, :formatter, :connection
6
+
7
+ def initialize(host, port, formatter)
8
+ @port = port
9
+ @host = host
10
+ @formatter = formatter
11
+ end
12
+
13
+ def publish(payload)
14
+ connect do |conn|
15
+ formatter.format(payload) do |msg|
16
+ conn.send(msg, 0)
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def connect
24
+ connection = UDPSocket.new
25
+ connection.connect(host, port)
26
+ yield(connection)
27
+ ensure
28
+ connection.close unless connection.closed?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ class Protor
2
+ class UDPFormatter
3
+ attr_reader :max_packet_size
4
+
5
+ LF = "\n".freeze
6
+
7
+ def initialize(max_packet_size)
8
+ @max_packet_size = max_packet_size
9
+ end
10
+
11
+ def format(registry)
12
+ return unless block_given?
13
+
14
+ str = ""
15
+ size = 0
16
+ registry.each do |entry|
17
+ line = stringify(entry)
18
+
19
+ if size + line.size > max_packet_size
20
+ yield(str)
21
+ str = line
22
+ size = line.size
23
+ else
24
+ str << line
25
+ size += line.size
26
+ end
27
+ end
28
+ yield(str)
29
+ end
30
+
31
+ private
32
+
33
+ def stringify(entry)
34
+ "#{ entry.name }|#{ entry.type }|".tap do |str|
35
+ str << "#{ additional_string(entry.additional) }|" unless entry.additional.empty?
36
+ str << "#{ labels_string(entry.labels) }|" unless entry.labels.empty?
37
+ str << "#{ entry.value }#{LF}"
38
+ end
39
+ end
40
+
41
+ def labels_string(labels)
42
+ labels.map{ |k, v| "#{k}=#{v}" }.join(';')
43
+ end
44
+
45
+ def additional_string(additional)
46
+ additional.join(';')
47
+ end
48
+ end
49
+ end
50
+
@@ -1,3 +1,3 @@
1
- module Protor
2
- VERSION = '0.0.11'
1
+ class Protor
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roland Rinfandi Utama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-22 00:00:00.000000000 Z
11
+ date: 2017-03-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -19,13 +19,12 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - README.md
21
21
  - lib/protor.rb
22
- - lib/protor/accumulator.rb
23
- - lib/protor/client.rb
24
- - lib/protor/configuration.rb
25
- - lib/protor/error.rb
26
- - lib/protor/observer.rb
27
- - lib/protor/payload.rb
22
+ - lib/protor/entry.rb
23
+ - lib/protor/entry_family.rb
24
+ - lib/protor/logger_client.rb
28
25
  - lib/protor/registry.rb
26
+ - lib/protor/udp_client.rb
27
+ - lib/protor/udp_formatter.rb
29
28
  - lib/protor/version.rb
30
29
  homepage: https://github.com/rolandhawk/protor-ruby
31
30
  licenses:
@@ -1,38 +0,0 @@
1
- module Protor
2
- class Accumulator
3
- def initialize(type)
4
- @data = {}
5
- @type = type
6
- end
7
-
8
- def inc(metric_name, value, labels = {})
9
- data[metric_name] ||= Hash.new(0)
10
- data[metric_name][labels] += value
11
- end
12
-
13
- def set(metric_name, value, labels = {})
14
- data[metric_name] ||= Hash.new(0)
15
- data[metric_name][labels] = value
16
- end
17
-
18
- def to_a
19
- array = []
20
-
21
- data.each do |metric_name, values|
22
- values.each do |labels, value|
23
- array << { metric_name: metric_name, labels: labels, value: value, type: type }
24
- end
25
- end
26
-
27
- return array
28
- end
29
-
30
- def empty?
31
- data.empty?
32
- end
33
-
34
- private
35
-
36
- attr_reader :type, :data
37
- end
38
- end
@@ -1,50 +0,0 @@
1
- require 'socket'
2
-
3
- module Protor
4
- class Client
5
- def initialize(configuration)
6
- @options = configuration
7
- @retries = 0
8
- end
9
-
10
- def publish(payload)
11
- connect
12
- payload.each do |message|
13
- send(message)
14
- end
15
- rescue Errno::EPERM, Errno::ECONNREFUSED => e
16
- options.logger.error(e)
17
- ensure
18
- close
19
- end
20
-
21
- private
22
-
23
- attr_reader :options, :connection, :retries
24
-
25
- def send(message)
26
- connection.send(message, 0)
27
- rescue Errno::EPERM => exception
28
- retries += 1
29
- if retries <= 3
30
- refresh && retry
31
- else
32
- raise exception
33
- end
34
- end
35
-
36
- def connect
37
- @connection = UDPSocket.new
38
- @connection.connect(options.host, options.port)
39
- end
40
-
41
- def refresh
42
- close
43
- connect
44
- end
45
-
46
- def close
47
- connection.close unless connection.closed?
48
- end
49
- end
50
- end
@@ -1,23 +0,0 @@
1
- require 'logger'
2
-
3
- module Protor
4
- class Configuration
5
- attr_writer :host, :port, :max_packet_size, :logger
6
-
7
- def host
8
- @host ||= 'localhost'
9
- end
10
-
11
- def port
12
- @port ||= 10601
13
- end
14
-
15
- def max_packet_size
16
- @max_packet_size ||= 56_607
17
- end
18
-
19
- def logger
20
- @logger ||= Logger.new(STDOUT)
21
- end
22
- end
23
- end
@@ -1,3 +0,0 @@
1
- module Protor
2
- class LabelError < StandardError; end
3
- end
@@ -1,47 +0,0 @@
1
- module Protor
2
- class Observer
3
- def initialize(type)
4
- @data = {}
5
- @type = type
6
- end
7
-
8
- def observe(metric_name, value, labels = {}, additional = [])
9
- data[metric_name] ||= { values: {} }
10
- data[metric_name][:values][labels] ||= []
11
-
12
- data[metric_name][:additional] = additional
13
- data[metric_name][:values][labels] << value
14
- end
15
-
16
- def to_a
17
- array = []
18
-
19
- data.each do |metric_name, values|
20
- first = true
21
- values[:values].each do |labels, value|
22
- value.each do |val|
23
- array << {
24
- metric_name: metric_name,
25
- labels: labels,
26
- value: val,
27
- additional: values[:additional],
28
- first: first,
29
- type: type
30
- }
31
- first = false
32
- end
33
- end
34
- end
35
-
36
- return array
37
- end
38
-
39
- def empty?
40
- data.empty?
41
- end
42
-
43
- private
44
-
45
- attr_reader :data, :type
46
- end
47
- end
@@ -1,106 +0,0 @@
1
- module Protor
2
- class Payload
3
-
4
- Lf = "\n".freeze
5
-
6
-
7
- def initialize(max_packet_size)
8
- @max_packet_size = max_packet_size
9
- @lines = []
10
- @total_size = 0
11
- end
12
-
13
- def add(data)
14
- data = data.dup
15
- data[:first] = true if lines.empty?
16
-
17
- if data[:labels]
18
- data[:labels].delete_if{ |k, v| v.to_s.empty? }
19
- else
20
- data[:labels] = {}
21
- end
22
-
23
- return false if packet_overflow?(data)
24
-
25
- self.common_labels = data[:labels]
26
- @total_size += data_size(data)
27
- @lines << data
28
- end
29
-
30
- def to_s
31
- str = first_line
32
- lines.each do |data|
33
- line = template(data)
34
- str << "#{line}#{Lf}"
35
- end
36
-
37
- return str
38
- end
39
-
40
- private
41
-
42
- attr_reader :common_labels, :lines, :total_size, :max_packet_size
43
-
44
- def data_size(data)
45
- size = 3
46
- [:metric_name, :value].each do |key|
47
- size += data[key].to_s.size
48
- end
49
-
50
- size += labels_string(data[:labels]).size + 1 if data[:labels]
51
-
52
- size += additional_string(data[:additional]).size + 1 if data[:first] && data[:additional]
53
-
54
- return size
55
- end
56
-
57
- def common_labels=(labels = {})
58
- @common_labels ||= labels.dup
59
- intersect(common_labels, labels)
60
- @common_labels.keep_if{ |k, v| labels.key?(k) }
61
- end
62
-
63
- def first_line
64
- if !common_labels || common_labels.empty?
65
- ""
66
- else
67
- "#{labels_string(common_labels)}#{Lf}"
68
- end
69
- end
70
-
71
- def template(data)
72
- labels = exclude_common(data[:labels])
73
-
74
- "#{ data[:metric_name] }|#{ data[:type][0] }|".tap do |str|
75
- str << "#{ additional_string(data[:additional]) }|" if data[:first] && data[:additional]
76
- str << "#{ labels_string(labels) }|" unless labels.empty?
77
- str << "#{ data[:value] }"
78
- end
79
- end
80
-
81
- def labels_string(labels)
82
- labels.map{ |k, v| "#{k}=#{v}" }.join(';')
83
- end
84
-
85
- def additional_string(additional)
86
- additional.join(';')
87
- end
88
-
89
- def intersect(a, b)
90
- a.keep_if{ |k, v| b[k] == v }
91
- end
92
-
93
- def exclude_common(labels)
94
- labels.keep_if{ |k, v| !common_labels[k] }
95
- end
96
-
97
- def packet_overflow?(data)
98
- backup = common_labels && common_labels.dup || data[:labels]
99
- intersect(backup, data[:labels])
100
- size = data_size(data)
101
-
102
- total_size + size - (labels_string(backup).size * lines.size) > max_packet_size
103
- end
104
- end
105
- end
106
-