snowman-io 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +4 -6
- data/bin/snowman +1 -1
- data/lib/config/mongoid.yml +5 -0
- data/lib/snowman-io.rb +62 -30
- data/lib/snowman-io/aggregate.rb +97 -0
- data/lib/snowman-io/api.rb +33 -65
- data/lib/snowman-io/api/agent.rb +27 -0
- data/lib/snowman-io/api/apps.rb +45 -0
- data/lib/snowman-io/api/auth_helpers.rb +76 -0
- data/lib/snowman-io/api/checks.rb +59 -0
- data/lib/snowman-io/api/extra/meteor.rb +45 -0
- data/lib/snowman-io/api/fridge.rb +14 -0
- data/lib/snowman-io/api/info.rb +30 -0
- data/lib/snowman-io/api/metrics.rb +115 -0
- data/lib/snowman-io/api/users.rb +231 -0
- data/lib/snowman-io/cli.rb +69 -0
- data/lib/snowman-io/launcher.rb +12 -11
- data/lib/snowman-io/loop/check_processor.rb +29 -0
- data/lib/snowman-io/loop/checks.rb +59 -0
- data/lib/snowman-io/loop/main.rb +43 -0
- data/lib/snowman-io/loop/ping.rb +25 -0
- data/lib/snowman-io/migration.rb +79 -0
- data/lib/snowman-io/models/aggregation.rb +15 -0
- data/lib/snowman-io/models/app.rb +61 -0
- data/lib/snowman-io/models/check.rb +48 -0
- data/lib/snowman-io/models/concerns/tokenable.rb +15 -0
- data/lib/snowman-io/models/data_point.rb +9 -0
- data/lib/snowman-io/models/deleted.rb +9 -0
- data/lib/snowman-io/models/following.rb +8 -0
- data/lib/snowman-io/models/metric.rb +36 -0
- data/lib/snowman-io/models/setting.rb +24 -0
- data/lib/snowman-io/models/user.rb +73 -0
- data/lib/snowman-io/options.rb +11 -3
- data/lib/snowman-io/report_mailer.rb +88 -0
- data/lib/snowman-io/reports.rb +16 -0
- data/lib/snowman-io/ui/AUTO_GENERATED_FOLDER +2 -0
- data/lib/snowman-io/ui/assets/ui-0e39dafcb798020fb855e325931c8451.css +1 -0
- data/lib/snowman-io/ui/assets/ui-d30809d0ae0a003d841fa95a352d624b.js +9 -0
- data/lib/snowman-io/ui/assets/vendor-7edfd1432c1bbd806306d5583c75b1fc.css +5 -0
- data/lib/snowman-io/ui/assets/vendor-c22e2ccc87c9bc7609b95939c308bc7f.js +24 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css.map +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.min.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css.map +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.min.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.svg +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.js +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.min.js +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/npm.js +0 -0
- data/lib/snowman-io/ui/crossdomain.xml +15 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/snowman-io/ui/index.html +175 -0
- data/lib/snowman-io/ui/robots.txt +2 -0
- data/lib/snowman-io/utils.rb +66 -0
- data/lib/snowman-io/version.rb +1 -1
- data/lib/snowman-io/views/layouts/custom.css +42 -0
- data/lib/snowman-io/views/layouts/main.html.erb +38 -0
- data/lib/snowman-io/views/layouts/styles.css +264 -0
- data/lib/snowman-io/views/layouts/transactional-email-templates-LICENSE +21 -0
- data/lib/snowman-io/views/report_mailer/check_triggered.html.erb +16 -0
- data/lib/snowman-io/views/report_mailer/checks/_human_last_value_limit.html.erb +2 -0
- data/lib/snowman-io/views/report_mailer/checks/_human_prev_day_datapoints_limit.html.erb +2 -0
- data/lib/snowman-io/views/report_mailer/daily_report.html.erb +40 -0
- data/lib/snowman-io/views/report_mailer/restore_password.html.erb +28 -0
- data/lib/snowman-io/views/report_mailer/send_invite.html.erb +32 -0
- data/lib/snowman-io/web.rb +28 -0
- data/lib/snowman-io/web_server.rb +107 -0
- data/snowman-io.gemspec +15 -5
- metadata +220 -49
- data/lib/snowman-io/api/public/README.md +0 -36
- data/lib/snowman-io/api/public/css/normalize.css +0 -406
- data/lib/snowman-io/api/public/css/style.css +0 -4
- data/lib/snowman-io/api/public/js/app.js +0 -13
- data/lib/snowman-io/api/public/js/libs/ember-1.8.1.js +0 -49740
- data/lib/snowman-io/api/public/js/libs/handlebars-v1.3.0.js +0 -2746
- data/lib/snowman-io/api/public/js/libs/jquery-1.10.2.js +0 -9789
- data/lib/snowman-io/api/public/tests/runner.css +0 -14
- data/lib/snowman-io/api/public/tests/runner.js +0 -13
- data/lib/snowman-io/api/public/tests/tests.js +0 -30
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.css +0 -244
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.js +0 -2212
- data/lib/snowman-io/api/views/index.erb +0 -26
- data/lib/snowman-io/api/views/layout.erb +0 -24
- data/lib/snowman-io/api/views/login.erb +0 -21
- data/lib/snowman-io/api/views/unpacking.erb +0 -21
- data/lib/snowman-io/check.rb +0 -49
- data/lib/snowman-io/check_result.rb +0 -15
- data/lib/snowman-io/checks/hosted_graphite.rb +0 -23
- data/lib/snowman-io/handler.rb +0 -27
- data/lib/snowman-io/notifiers/slack.rb +0 -76
- data/lib/snowman-io/processor.rb +0 -32
- data/lib/snowman-io/scheduler.rb +0 -42
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module SnowmanIO
|
4
|
+
# The command line interface for SnowmanIO.
|
5
|
+
class CLI
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def self.run
|
9
|
+
options = Options.new.parse!(ARGV)
|
10
|
+
new(options).run
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
setup_logger
|
19
|
+
|
20
|
+
# Self-pipe for deferred signal-handling (http://cr.yp.to/docs/selfpipe.html)
|
21
|
+
self_read, self_write = IO.pipe
|
22
|
+
|
23
|
+
%w(INT TERM USR1 USR2 TTIN).each do |sig|
|
24
|
+
begin
|
25
|
+
trap sig do
|
26
|
+
self_write.puts(sig)
|
27
|
+
end
|
28
|
+
rescue ArgumentError
|
29
|
+
puts "Signal #{sig} not supported"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
launcher = Launcher.new(options)
|
34
|
+
|
35
|
+
begin
|
36
|
+
launcher.start
|
37
|
+
while readable_io = IO.select([self_read])
|
38
|
+
signal = readable_io.first[0].gets.strip
|
39
|
+
handle_signal(signal)
|
40
|
+
end
|
41
|
+
rescue Interrupt
|
42
|
+
SnowmanIO.logger.info 'Shutting down'
|
43
|
+
launcher.stop
|
44
|
+
exit(0)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def handle_signal(sig)
|
51
|
+
SnowmanIO.logger.debug "Received #{sig} signal"
|
52
|
+
case sig
|
53
|
+
when 'TERM'
|
54
|
+
raise Interrupt
|
55
|
+
when 'INT'
|
56
|
+
raise Interrupt
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup_logger
|
61
|
+
Celluloid.logger = (options[:verbose] ? SnowmanIO.logger : nil)
|
62
|
+
if options[:verbose]
|
63
|
+
SnowmanIO.logger.level = ::Logger::DEBUG
|
64
|
+
else
|
65
|
+
SnowmanIO.logger.level = ::Logger::INFO
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/snowman-io/launcher.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
-
require 'snowman-io/scheduler'
|
2
|
-
require 'snowman-io/handler'
|
3
|
-
|
4
1
|
module SnowmanIO
|
5
2
|
class Launcher
|
6
3
|
include Celluloid
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(checks)
|
11
|
-
@handler = Handler.new_link
|
12
|
-
@scheduler = Scheduler.new_link(checks)
|
13
|
-
@scheduler.handler = handler
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
14
7
|
end
|
15
8
|
|
16
9
|
def start
|
17
|
-
|
10
|
+
Migration.new.migrate
|
11
|
+
app = Rack::Cascade.new [API::Root, Web]
|
12
|
+
@web_server = WebServer.supervise_as(:web_server, app, @options.slice(:port, :host, :verbose))
|
13
|
+
@ping = Loop::Ping.supervise_as(:ping)
|
14
|
+
@main = Loop::Main.supervise_as(:main)
|
15
|
+
@checks = Loop::Checks.supervise_as(:checks)
|
18
16
|
end
|
19
17
|
|
20
18
|
def stop
|
21
|
-
|
19
|
+
@checks.terminate
|
20
|
+
@main.terminate
|
21
|
+
@ping.terminate
|
22
|
+
@web_server.terminate # TODO: shutdown blocking?
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
module Loop
|
3
|
+
class CheckProcessor
|
4
|
+
def initialize(check)
|
5
|
+
@check = check
|
6
|
+
@metric = check.metric
|
7
|
+
end
|
8
|
+
|
9
|
+
def process
|
10
|
+
if @check.template == Check::TEMPLATE_LAST_VALUE_LIMIT
|
11
|
+
@check.cmp_fn.call(@metric.last_value, @check.value)
|
12
|
+
|
13
|
+
elsif @check.template == Check::TEMPLATE_PREV_DAY_DATAPOINTS_LIMIT
|
14
|
+
# use aggregation for prev day
|
15
|
+
at = Time.now.beginning_of_day - 1.day
|
16
|
+
if @metric.created_at < at # require full gather day
|
17
|
+
count = @metric.aggregations.where("precision" => "daily", "at" => at).first.try(&:count).to_i
|
18
|
+
@check.cmp_fn.call(count, @check.value)
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
else
|
24
|
+
raise "Unknown check template: #{@check.template}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'snowman-io/loop/check_processor'
|
2
|
+
|
3
|
+
module SnowmanIO
|
4
|
+
module Loop
|
5
|
+
class Checks
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
after(1) { tick }
|
10
|
+
end
|
11
|
+
|
12
|
+
def tick
|
13
|
+
perform
|
14
|
+
after(3) { tick }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def perform
|
20
|
+
Check.each do |check|
|
21
|
+
result = CheckProcessor.new(check).process
|
22
|
+
send_mail = false
|
23
|
+
check.last_run_at = DateTime.now
|
24
|
+
if result
|
25
|
+
puts "Check for #{check.metric.name} triggered"
|
26
|
+
unless check.triggered
|
27
|
+
send_mail = true
|
28
|
+
end
|
29
|
+
check.triggered = true
|
30
|
+
check.last_status = Check::STATUS_FAILED
|
31
|
+
else
|
32
|
+
check.last_status = Check::STATUS_OK
|
33
|
+
end
|
34
|
+
check.save!
|
35
|
+
|
36
|
+
if send_mail
|
37
|
+
ReportMailer.check_triggered(
|
38
|
+
check,
|
39
|
+
check.last_run_at,
|
40
|
+
Setting.get(SnowmanIO::BASE_URL_KEY),
|
41
|
+
check.user.email,
|
42
|
+
true
|
43
|
+
).deliver_now
|
44
|
+
|
45
|
+
check.user.followers.each do |user|
|
46
|
+
ReportMailer.check_triggered(
|
47
|
+
check,
|
48
|
+
check.last_run_at,
|
49
|
+
Setting.get(SnowmanIO::BASE_URL_KEY),
|
50
|
+
user.email,
|
51
|
+
false
|
52
|
+
).deliver_now
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
module Loop
|
3
|
+
class Main
|
4
|
+
include Celluloid
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
after(1) { tick }
|
8
|
+
end
|
9
|
+
|
10
|
+
def tick
|
11
|
+
perform
|
12
|
+
after(3) { tick }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def perform
|
18
|
+
now = Time.now
|
19
|
+
|
20
|
+
# next time let send report for today
|
21
|
+
next_report_date = Time.now.beginning_of_day
|
22
|
+
|
23
|
+
# aggregate
|
24
|
+
start = Time.now.to_f
|
25
|
+
Aggregate.metrics_aggregate_5min
|
26
|
+
Aggregate.metrics_aggregate_hour
|
27
|
+
Aggregate.metrics_aggregate_daily
|
28
|
+
Aggregate.metrics_clean_old
|
29
|
+
|
30
|
+
# init report time
|
31
|
+
unless Setting.get(SnowmanIO::NEXT_REPORT_DATE_KEY)
|
32
|
+
Setting.set(SnowmanIO::NEXT_REPORT_DATE_KEY, next_report_date.to_i)
|
33
|
+
end
|
34
|
+
|
35
|
+
# send report at 7:00 next day
|
36
|
+
if now.to_i > Setting.get(SnowmanIO::NEXT_REPORT_DATE_KEY) + 1.day + 7.hours
|
37
|
+
Reports.report_send(Time.at(Setting.get(SnowmanIO::NEXT_REPORT_DATE_KEY)))
|
38
|
+
Setting.set(SnowmanIO::NEXT_REPORT_DATE_KEY, next_report_date.to_i)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
module Loop
|
3
|
+
# Ping itself every 5 minutes to be in fit
|
4
|
+
class Ping
|
5
|
+
include Celluloid
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
after(10) { tick }
|
9
|
+
end
|
10
|
+
|
11
|
+
def tick
|
12
|
+
perform
|
13
|
+
after(5*60) { tick }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def perform
|
19
|
+
if base_url = Setting.get(SnowmanIO::BASE_URL_KEY)
|
20
|
+
open(base_url + "/ping")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
# Helpfull class to seed data and update DB
|
3
|
+
class Migration
|
4
|
+
def initialize
|
5
|
+
@db = Mongoid::Sessions.default
|
6
|
+
puts "[DEBUG] #{@db[:snowman_io_schema].find.to_a.inspect}"
|
7
|
+
@done_versions = @db[:snowman_io_schema].find.map { |c| c["version"] }
|
8
|
+
@migration_versions = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def migrate
|
12
|
+
SnowmanIO.logger.info "Migration start"
|
13
|
+
|
14
|
+
migration "Set boundary template for all checks" do
|
15
|
+
@db[:snowman_io_checks].find().update_all("$set" => {"template" => "boundary"})
|
16
|
+
end
|
17
|
+
|
18
|
+
migration "boundary => last_value_limit" do
|
19
|
+
@db[:snowman_io_checks].find({template: "boundary"}).update_all("$set" => {"template" => "last_value_limit"})
|
20
|
+
end
|
21
|
+
|
22
|
+
migration "daily_datapoints => prev_day_datapoints_limit" do
|
23
|
+
@db[:snowman_io_checks].find({template: "daily_datapoints"}).update_all("$set" => {"template" => "prev_day_datapoints_limit"})
|
24
|
+
end
|
25
|
+
|
26
|
+
migration "set owner to each check" do
|
27
|
+
if user = @db[:snowman_io_users].find.first
|
28
|
+
@db[:snowman_io_checks].find.update_all("$set" => {"user_id" => user["_id"]})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
migration "users timestamps" do
|
33
|
+
@db[:snowman_io_users].find.update_all("$set" => {"created_at" => Time.now})
|
34
|
+
@db[:snowman_io_users].find.update_all("$set" => {"updated_at" => Time.now})
|
35
|
+
end
|
36
|
+
|
37
|
+
migration "users daily_report" do
|
38
|
+
@db[:snowman_io_users].find.update_all("$set" => {"daily_report" => true})
|
39
|
+
end
|
40
|
+
|
41
|
+
migration "users invite_token" do
|
42
|
+
@db[:snowman_io_users].find.update_all("$set" => {"invite_token" => ""})
|
43
|
+
end
|
44
|
+
|
45
|
+
migration "users invite_send_count" do
|
46
|
+
@db[:snowman_io_users].find.update_all("$set" => {"invite_send_count" => 0})
|
47
|
+
end
|
48
|
+
|
49
|
+
migration "users status" do
|
50
|
+
@db[:snowman_io_users].find.update_all("$set" => {"status" => "wait_invite"})
|
51
|
+
@db[:snowman_io_users].where(invite_token: "").update_all("$set" => {"status" => "active"})
|
52
|
+
end
|
53
|
+
|
54
|
+
migration "users name" do
|
55
|
+
@db[:snowman_io_users].where(status: "active").each do |record|
|
56
|
+
@db[:snowman_io_users].where(_id: record["_id"]).update_all("$set" => {"name" => record["email"]})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
SnowmanIO.logger.info "Migration done"
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def migration(version, &block)
|
66
|
+
if @migration_versions.include?(version)
|
67
|
+
raise "Duplicate migration version '#{version}'"
|
68
|
+
end
|
69
|
+
@migration_versions.push version
|
70
|
+
|
71
|
+
return if @done_versions.include?(version)
|
72
|
+
|
73
|
+
SnowmanIO.logger.info "Apply: #{version} ..."
|
74
|
+
yield
|
75
|
+
@db[:snowman_io_schema].insert(version: version)
|
76
|
+
SnowmanIO.logger.info "Apply: #{version} ... OK"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
class Aggregation
|
3
|
+
include Mongoid::Document
|
4
|
+
belongs_to :metric
|
5
|
+
|
6
|
+
field :precision, type: String
|
7
|
+
field :at, type: DateTime
|
8
|
+
field :min, type: Float
|
9
|
+
field :avg, type: Float
|
10
|
+
field :up, type: Float
|
11
|
+
field :max, type: Float
|
12
|
+
field :sum, type: Float
|
13
|
+
field :count, type: Integer
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
class App
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
include Concerns::Tokenable
|
6
|
+
has_many :metrics, dependent: :destroy
|
7
|
+
|
8
|
+
field :name, type: String
|
9
|
+
field :token, type: String
|
10
|
+
|
11
|
+
validates :name, :token, presence: true
|
12
|
+
|
13
|
+
before_validation on: :create do
|
14
|
+
self.token = generate_token(:token)
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json(options = {})
|
18
|
+
super(options.merge(methods: [:datapoints, :metric_ids])).tap do |o|
|
19
|
+
o["id"] = o.delete("_id").to_s
|
20
|
+
o["metric_ids"] = o["metric_ids"].map(&:to_s)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns amount of datapoints for `at` and day before
|
25
|
+
def daily_metrics(at)
|
26
|
+
json = {}
|
27
|
+
|
28
|
+
today = at.beginning_of_day
|
29
|
+
yesterday = at.beginning_of_day - 1.day
|
30
|
+
json["today"] = {"at" => today.strftime("%Y-%m-%d"), "count" => 0}
|
31
|
+
json["yesterday"] = {"at" => yesterday.strftime("%Y-%m-%d"), "count" => 0}
|
32
|
+
json["total"] = {"count" => 0}
|
33
|
+
|
34
|
+
# TODO: impl it more performable
|
35
|
+
metrics.each do |metric|
|
36
|
+
if aggr = metric.aggregations.where(precision: "daily", at: today).first
|
37
|
+
json["today"]["count"] += aggr.count.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
if aggr = metric.aggregations.where(precision: "daily", at: yesterday).first
|
41
|
+
json["yesterday"]["count"] += aggr.count.to_i
|
42
|
+
end
|
43
|
+
|
44
|
+
json["total"]["count"] += metric.aggregations.where(precision: "daily").sum(:count).to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
json
|
48
|
+
end
|
49
|
+
|
50
|
+
def register_metric_value(name, kind, value, at = Time.now)
|
51
|
+
metric = metrics.where(name: name, kind: kind).first_or_create!
|
52
|
+
metric.update_attributes!(last_value: value, last_value_updated_at: Time.now)
|
53
|
+
metric.data_points.create!(at: at, value: value)
|
54
|
+
touch
|
55
|
+
end
|
56
|
+
|
57
|
+
def datapoints
|
58
|
+
daily_metrics(Time.now)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
class Check
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
|
6
|
+
STATUS_NEVER_RUNNED = "NEVER RUNNED"
|
7
|
+
STATUS_OK = "OK"
|
8
|
+
STATUS_FAILED = "FAILED"
|
9
|
+
|
10
|
+
TEMPLATE_LAST_VALUE_LIMIT = "last_value_limit"
|
11
|
+
TEMPLATE_PREV_DAY_DATAPOINTS_LIMIT = "prev_day_datapoints_limit"
|
12
|
+
|
13
|
+
belongs_to :metric
|
14
|
+
belongs_to :user
|
15
|
+
|
16
|
+
# Each check should be one of available templates. Each metric is compatible only
|
17
|
+
# with some templates.
|
18
|
+
field :template, type: String
|
19
|
+
|
20
|
+
# TEMPLATE_LAST_VALUE_LIMIT, TEMPLATE_PREV_DAY_DATAPOINTS_LIMIT
|
21
|
+
field :cmp, type: String
|
22
|
+
field :value, type: Float
|
23
|
+
|
24
|
+
# COMMON
|
25
|
+
field :triggered, type: Boolean, default: false
|
26
|
+
field :last_run_at, type: DateTime
|
27
|
+
field :last_status, type: String, default: STATUS_NEVER_RUNNED
|
28
|
+
|
29
|
+
def as_json(options = {})
|
30
|
+
super(options).tap do |o|
|
31
|
+
o["id"] = o.delete("_id").to_s
|
32
|
+
o["metric_id"] = o["metric_id"].to_s
|
33
|
+
o["user_id"] = o["user_id"].to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def cmp_fn
|
38
|
+
case cmp
|
39
|
+
when "more"
|
40
|
+
-> (a, b) { a ? a > b : false }
|
41
|
+
when "less"
|
42
|
+
-> (a, b) { a ? a < b : false }
|
43
|
+
else
|
44
|
+
raise "unreachable"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|