Class: ScoutApm::Instruments::Process::ProcessCpu

Inherits:
Object
  • Object
show all
Defined in:
lib/scout_apm/instruments/process/process_cpu.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context) ⇒ ProcessCpu

Returns a new instance of ProcessCpu.



9
10
11
12
13
14
15
16
17
18
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 9

def initialize(context)
  @context = context

  @num_processors = [context.environment.processors, 1].compact.max

  t = ::Process.times
  @last_run = Time.now
  @last_utime = t.utime
  @last_stime = t.stime
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



7
8
9
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 7

def context
  @context
end

#last_runObject

Returns the value of attribute last_run.



6
7
8
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 6

def last_run
  @last_run
end

#last_stimeObject

Returns the value of attribute last_stime.



6
7
8
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 6

def last_stime
  @last_stime
end

#last_utimeObject

Returns the value of attribute last_utime.



6
7
8
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 6

def last_utime
  @last_utime
end

#num_processorsObject (readonly)

Returns the value of attribute num_processors.



5
6
7
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 5

def num_processors
  @num_processors
end

Instance Method Details

#human_nameObject



28
29
30
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 28

def human_name
  "Process CPU"
end

#loggerObject



102
103
104
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 102

def logger
  context.logger
end

#metric_nameObject



24
25
26
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 24

def metric_name
  "Utilization"
end

#metric_typeObject



20
21
22
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 20

def metric_type
  "CPU"
end

#metrics(timestamp, store) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 32

def metrics(timestamp, store)
  result = run
  if result
    meta = MetricMeta.new("#{metric_type}/#{metric_name}")
    stat = MetricStats.new(false)
    stat.update!(result)
    store.track!({ meta => stat }, :timestamp => timestamp)
  else
    {}
  end

end

#runObject

TODO: Figure out a good default instead of nil



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 46

def run
  res = nil

  t = ::Process.times
  now = Time.now
  utime = t.utime
  stime = t.stime

  wall_clock_elapsed  = now - last_run
  if wall_clock_elapsed < 0
    save_times(now, utime, stime)
    logger.info "#{human_name}: Negative time elapsed.  now: #{now}, last_run: #{last_run}, total time: #{wall_clock_elapsed}."
    return nil
  end

  utime_elapsed   = utime - last_utime
  stime_elapsed   = stime - last_stime
  process_elapsed = utime_elapsed + stime_elapsed

  # This can happen right after a fork.  This class starts up in
  # pre-fork, records {u,s}time, then forks. This resets {u,s}time to 0
  if process_elapsed < 0
    save_times(now, utime, stime)
    logger.debug "#{human_name}: Negative process time elapsed.  utime: #{utime_elapsed}, stime: #{stime_elapsed}, total time: #{process_elapsed}. This is normal to see when starting a forking web server."
    return nil
  end

  # Normalized to # of processors
  normalized_wall_clock_elapsed = wall_clock_elapsed * num_processors

  # If somehow we run for 0 seconds between calls, don't try to divide by 0
  res = if normalized_wall_clock_elapsed == 0
          0
        else
          ( process_elapsed / normalized_wall_clock_elapsed )*100
        end

  if res < 0
    save_times(now, utime, stime)
    logger.info "#{human_name}: Negative CPU.  #{process_elapsed} / #{normalized_wall_clock_elapsed} * 100 ==> #{res}"
    return nil
  end

  save_times(now, utime, stime)

  logger.debug "#{human_name}: #{res.inspect} [#{num_processors} CPU(s)]"

  return res
end

#save_times(now, utime, stime) ⇒ Object



96
97
98
99
100
# File 'lib/scout_apm/instruments/process/process_cpu.rb', line 96

def save_times(now, utime, stime)
  self.last_run = now
  self.last_utime = utime
  self.last_stime = stime
end