Skip to content

Commit

Permalink
first pass on metrics data model
Browse files Browse the repository at this point in the history
  • Loading branch information
anmarchenko committed Jun 25, 2024
1 parent 141381e commit 62591c6
Show file tree
Hide file tree
Showing 2 changed files with 247 additions and 0 deletions.
145 changes: 145 additions & 0 deletions lib/datadog/core/telemetry/metric.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# frozen_string_literal: true

module Datadog
module Core
module Telemetry
# Telemetry metrics data model
module Metric
def self.metric_id(type, name, tags = [])
"#{type}:#{name}:#{tags.join(',')}"
end

# Base class for all metric types
class Base
attr_reader :name, :tags, :values, :common, :interval

def initialize(name, tags: {}, common: true, interval: nil)
@name = name
@values = []
@tags = tags_to_array(tags)
@common = common
@interval = interval
end

def track(value); end

def type; end

def to_h
# @type var res: Hash[Symbol, untyped]
res = {
metric: name,
points: values,
type: type,
tags: tags, # move to method
common: common
}
res[:interval] = interval if interval
res
end

private

def tags_to_array(tags)
return tags if tags.is_a?(Array)

tags.map { |k, v| "#{k}:#{v}" }
end
end

# Count metric adds up all the submitted values in a time interval. This would be suitable for a
# metric tracking the number of website hits, for instance.
class Count < Base
TYPE = 'count'

def type
TYPE
end

def inc(value = 1)
track(value)
end

def dec(value = 1)
track(-value)
end

def track(value)
if values.empty?
values << [Time.now.to_i, value]
else
values[0][0] = Time.now.to_i
values[0][1] += value
end
end
end

# A gauge type takes the last value reported during the interval. This type would make sense for tracking RAM or
# CPU usage, where taking the last value provides a representative picture of the host’s behavior during the time
# interval.
class Gauge < Base
TYPE = 'gauge'

def type
TYPE
end

def track(value)
if values.empty?
values << [Time.now.to_i, value]
else
values[0][0] = Time.now.to_i
values[0][1] = value
end
end
end

# The rate type takes the count and divides it by the length of the time interval. This is useful if you’re
# interested in the number of hits per second.
class Rate < Base
TYPE = 'rate'

def initialize(name, tags: {}, common: true, interval: nil)
super

@value = 0
end

def type
TYPE
end

def track(value = 1.0)
@value += value

rate = interval ? @value.to_f / interval : 0.0
@values = [[Time.now.to_i, rate]]
end
end

# Distribution metric represents the global statistical distribution of a set of values.
class Distribution < Base
TYPE = 'distributions'

def type
TYPE
end

def track(value)
values << value
end

# distribution metric data does not have type field
def to_h
{
metric: name,
points: values,
tags: tags, # move to method
common: common
}
end
end
end
end
end
end
102 changes: 102 additions & 0 deletions sig/datadog/core/telemetry/metric.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
module Datadog
module Core
module Telemetry
module Metric
type metric_type = "count" | "gauge" | "rate" | "distributions" | nil

type input_value = Integer | Float

type metric_value = Array[input_value]
type distribution_value = input_value

type tags_input = ::Hash[String, String] | Array[String]

def self.metric_id: (metric_type type, String name, ?Array[String] tags) -> ::String

class Base
@name: String

@values: Array[untyped]

@tags: Array[String]

@common: bool

@interval: Integer?

attr_reader name: String

attr_reader tags: Array[String]

attr_reader values: Array[untyped]

attr_reader common: bool

attr_reader interval: Integer?

def initialize: (String name, ?tags: tags_input, ?common: bool, ?interval: Integer?) -> void

def track: (Numeric value) -> void

def type: () -> metric_type

def to_h: () -> Hash[Symbol, untyped]

private

def tags_to_array: (tags_input tags) -> Array[String]
end

class Count < Base
TYPE: "count"

@values: Array[metric_value]
attr_reader values: Array[metric_value]

def type: () -> "count"

def inc: (?::Integer value) -> void

def dec: (?::Integer value) -> void

def track: (Integer value) -> void
end

class Gauge < Base
TYPE: "gauge"

def type: () -> "gauge"

def track: (input_value value) -> void
end

class Rate < Base
@value: Float

@values: Array[metric_value]
attr_reader values: Array[metric_value]

TYPE: "rate"

def initialize: (String name, ?tags: tags_input, ?common: bool, ?interval: Integer?) -> void

def type: () -> "rate"

def track: (?::Float value) -> void
end

class Distribution < Base
TYPE: "distributions"

@values: Array[distribution_value]
attr_reader values: Array[distribution_value]

def type: () -> "distributions"

def track: (input_value value) -> void
def to_h: () -> { metric: String, points: Array[distribution_value], tags: Array[String], common: bool }
end
end
end
end
end

0 comments on commit 62591c6

Please sign in to comment.