blazer 1.9.0 → 2.0.0
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/CONTRIBUTING.md +9 -7
- data/README.md +59 -19
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.svg +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff2 +0 -0
- data/app/assets/javascripts/blazer/Chart.js +4195 -3884
- data/app/assets/javascripts/blazer/Sortable.js +1493 -1097
- data/app/assets/javascripts/blazer/ace/ace.js +21294 -4
- data/app/assets/javascripts/blazer/ace/ext-language_tools.js +1991 -3
- data/app/assets/javascripts/blazer/ace/mode-sql.js +110 -1
- data/app/assets/javascripts/blazer/ace/snippets/sql.js +40 -1
- data/app/assets/javascripts/blazer/ace/snippets/text.js +14 -1
- data/app/assets/javascripts/blazer/ace/theme-twilight.js +116 -1
- data/app/assets/javascripts/blazer/application.js +4 -3
- data/app/assets/javascripts/blazer/bootstrap.js +623 -612
- data/app/assets/javascripts/blazer/chartkick.js +1769 -1248
- data/app/assets/javascripts/blazer/daterangepicker.js +263 -115
- data/app/assets/javascripts/blazer/highlight.min.js +3 -0
- data/app/assets/javascripts/blazer/{jquery_ujs.js → jquery-ujs.js} +161 -75
- data/app/assets/javascripts/blazer/jquery.js +9506 -9450
- data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +321 -259
- data/app/assets/javascripts/blazer/moment-timezone-with-data.js +1212 -0
- data/app/assets/javascripts/blazer/queries.js +1 -1
- data/app/assets/javascripts/blazer/routes.js +1 -1
- data/app/assets/javascripts/blazer/selectize.js +3828 -3604
- data/app/assets/javascripts/blazer/stupidtable.js +255 -88
- data/app/assets/javascripts/blazer/vue.js +8015 -4583
- data/app/assets/stylesheets/blazer/application.css +13 -1
- data/app/assets/stylesheets/blazer/bootstrap.css.erb +879 -325
- data/app/assets/stylesheets/blazer/daterangepicker.css +269 -0
- data/app/assets/stylesheets/blazer/selectize.default.css +26 -10
- data/app/controllers/blazer/base_controller.rb +7 -1
- data/app/controllers/blazer/checks_controller.rb +1 -1
- data/app/controllers/blazer/queries_controller.rb +7 -8
- data/app/mailers/blazer/slack_notifier.rb +76 -0
- data/app/models/blazer/check.rb +9 -0
- data/app/views/blazer/_variables.html.erb +38 -18
- data/app/views/blazer/checks/_form.html.erb +9 -1
- data/app/views/blazer/checks/index.html.erb +4 -1
- data/app/views/blazer/queries/_form.html.erb +2 -2
- data/app/views/blazer/queries/docs.html.erb +138 -0
- data/app/views/blazer/queries/show.html.erb +1 -1
- data/app/views/layouts/blazer/application.html.erb +2 -2
- data/config/routes.rb +1 -1
- data/lib/blazer.rb +22 -15
- data/lib/blazer/adapters/bigquery_adapter.rb +5 -4
- data/lib/blazer/adapters/elasticsearch_adapter.rb +14 -17
- data/lib/blazer/adapters/mongodb_adapter.rb +1 -1
- data/lib/blazer/adapters/sql_adapter.rb +7 -1
- data/lib/blazer/data_source.rb +0 -1
- data/lib/blazer/engine.rb +2 -0
- data/lib/blazer/run_statement_job.rb +6 -9
- data/lib/blazer/version.rb +1 -1
- data/lib/generators/blazer/templates/{config.yml → config.yml.tt} +3 -0
- data/lib/generators/blazer/templates/{install.rb → install.rb.tt} +1 -0
- data/lib/tasks/blazer.rake +2 -1
- metadata +24 -30
- data/.gitattributes +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -7
- data/.gitignore +0 -14
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/app/assets/javascripts/blazer/highlight.pack.js +0 -1
- data/app/assets/javascripts/blazer/moment-timezone.js +0 -1007
- data/app/assets/stylesheets/blazer/daterangepicker-bs3.css +0 -375
- data/app/views/blazer/queries/schema.html.erb +0 -20
- data/blazer.gemspec +0 -27
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
|
|
3
|
+
module Blazer
|
|
4
|
+
class SlackNotifier
|
|
5
|
+
def self.state_change(check, state, state_was, rows_count, error, check_type)
|
|
6
|
+
check.split_slack_channels.each do |channel|
|
|
7
|
+
text =
|
|
8
|
+
if error
|
|
9
|
+
error
|
|
10
|
+
elsif rows_count > 0 && check_type == "bad_data"
|
|
11
|
+
pluralize(rows_count, "row")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
payload = {
|
|
15
|
+
channel: channel,
|
|
16
|
+
attachments: [
|
|
17
|
+
{
|
|
18
|
+
title: escape("Check #{state.titleize}: #{check.query.name}"),
|
|
19
|
+
title_link: query_url(check.query_id),
|
|
20
|
+
text: escape(text),
|
|
21
|
+
color: state == "passing" ? "good" : "danger"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
post(Blazer.slack_webhook_url, payload)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.failing_checks(channel, checks)
|
|
31
|
+
text =
|
|
32
|
+
checks.map do |check|
|
|
33
|
+
"<#{query_url(check.query_id)}|#{escape(check.query.name)}> #{escape(check.state)}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
payload = {
|
|
37
|
+
channel: channel,
|
|
38
|
+
attachments: [
|
|
39
|
+
{
|
|
40
|
+
title: escape("#{pluralize(checks.size, "Check")} Failing"),
|
|
41
|
+
text: text.join("\n"),
|
|
42
|
+
color: "warning"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
post(Blazer.slack_webhook_url, payload)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# https://api.slack.com/docs/message-formatting#how_to_escape_characters
|
|
51
|
+
# - Replace the ampersand, &, with &
|
|
52
|
+
# - Replace the less-than sign, < with <
|
|
53
|
+
# - Replace the greater-than sign, > with >
|
|
54
|
+
# That's it. Don't HTML entity-encode the entire message.
|
|
55
|
+
def self.escape(str)
|
|
56
|
+
str.gsub("&", "&").gsub("<", "<").gsub(">", ">") if str
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.pluralize(*args)
|
|
60
|
+
ActionController::Base.helpers.pluralize(*args)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.query_url(id)
|
|
64
|
+
Blazer::Engine.routes.url_helpers.query_url(id, ActionMailer::Base.default_url_options)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.post(url, payload)
|
|
68
|
+
uri = URI.parse(url)
|
|
69
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
70
|
+
http.use_ssl = true
|
|
71
|
+
http.open_timeout = 3
|
|
72
|
+
http.read_timeout = 5
|
|
73
|
+
http.post(uri.request_uri, payload.to_json)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/app/models/blazer/check.rb
CHANGED
|
@@ -14,6 +14,14 @@ module Blazer
|
|
|
14
14
|
emails.to_s.downcase.split(",").map(&:strip)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def split_slack_channels
|
|
18
|
+
if Blazer.slack?
|
|
19
|
+
slack_channels.to_s.downcase.split(",").map(&:strip)
|
|
20
|
+
else
|
|
21
|
+
[]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
def update_state(result)
|
|
18
26
|
check_type =
|
|
19
27
|
if respond_to?(:check_type)
|
|
@@ -61,6 +69,7 @@ module Blazer
|
|
|
61
69
|
# do not notify on creation, except when not passing
|
|
62
70
|
if (state_was != "new" || state != "passing") && state != state_was && emails.present?
|
|
63
71
|
Blazer::CheckMailer.state_change(self, state, state_was, result.rows.size, message, result.columns, result.rows.first(10).as_json, result.column_types, check_type).deliver_now
|
|
72
|
+
Blazer::SlackNotifier.state_change(self, state, state_was, result.rows.size, message, check_type)
|
|
64
73
|
end
|
|
65
74
|
save! if changed?
|
|
66
75
|
end
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
<% if @bind_vars.any? %>
|
|
2
|
+
<script>
|
|
3
|
+
<%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
|
|
4
|
+
var now = moment.tz(timeZone)
|
|
5
|
+
var format = "YYYY-MM-DD"
|
|
6
|
+
|
|
7
|
+
function toDate(time) {
|
|
8
|
+
return moment.tz(time.format(format), timeZone)
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
2
11
|
<form id="bind" method="get" action="<%= action %>" class="form-inline" style="margin-bottom: 10px;">
|
|
3
12
|
<% date_vars = ["start_time", "end_time"] %>
|
|
4
13
|
<% if (date_vars - @bind_vars).empty? %>
|
|
@@ -16,18 +25,37 @@
|
|
|
16
25
|
create: true
|
|
17
26
|
});
|
|
18
27
|
</script>
|
|
19
|
-
<%
|
|
20
|
-
<%=
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
<% elsif var.end_with?("_at") || var == "start_time" || var == "end_time" %>
|
|
29
|
+
<%= hidden_field_tag var, params[var] %>
|
|
30
|
+
|
|
31
|
+
<div class="selectize-control single" style="width: 200px;">
|
|
32
|
+
<div id="<%= var %>-select" class="selectize-input" style="display: inline-block;">
|
|
33
|
+
<span>Select a date</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
(function() {
|
|
39
|
+
var input = $("#<%= var %>")
|
|
40
|
+
var datePicker = $("#<%= var %>-select")
|
|
41
|
+
datePicker.daterangepicker({
|
|
42
|
+
singleDatePicker: true,
|
|
43
|
+
locale: {format: format},
|
|
44
|
+
autoUpdateInput: false,
|
|
45
|
+
startDate: input.val().length > 0 ? moment.tz(input.val(), timeZone) : now
|
|
46
|
+
})
|
|
24
47
|
// hack to start with empty date
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
48
|
+
datePicker.on("apply.daterangepicker", function(ev, picker) {
|
|
49
|
+
datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
|
|
50
|
+
input.val(toDate(picker.startDate).utc().format())
|
|
51
|
+
submitIfCompleted($("#<%= var %>").closest("form"))
|
|
28
52
|
});
|
|
29
|
-
|
|
30
|
-
|
|
53
|
+
var picker = datePicker.data("daterangepicker")
|
|
54
|
+
datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
|
|
55
|
+
})()
|
|
56
|
+
</script>
|
|
57
|
+
<% else %>
|
|
58
|
+
<%= text_field_tag var, params[var], style: "width: 120px; margin-right: 20px;", autofocus: i == 0 && !var.end_with?("_at") && !params[var], class: "form-control" %>
|
|
31
59
|
<% end %>
|
|
32
60
|
<% end %>
|
|
33
61
|
|
|
@@ -44,18 +72,10 @@
|
|
|
44
72
|
</div>
|
|
45
73
|
|
|
46
74
|
<script>
|
|
47
|
-
<%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
|
|
48
|
-
var format = "YYYY-MM-DD"
|
|
49
|
-
var now = moment.tz(timeZone)
|
|
50
|
-
|
|
51
75
|
function dateStr(daysAgo) {
|
|
52
76
|
return now.clone().subtract(daysAgo || 0, "days").format(format)
|
|
53
77
|
}
|
|
54
78
|
|
|
55
|
-
function toDate(time) {
|
|
56
|
-
return moment.tz(time.format(format), timeZone)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
79
|
function setTimeInputs(start, end) {
|
|
60
80
|
$("#start_time").val(toDate(start).utc().format())
|
|
61
81
|
$("#end_time").val(toDate(end).endOf("day").utc().format())
|
|
@@ -60,7 +60,15 @@
|
|
|
60
60
|
<%= f.label :emails %>
|
|
61
61
|
<%= f.text_field :emails, placeholder: "Optional, comma separated", class: "form-control" %>
|
|
62
62
|
</div>
|
|
63
|
-
|
|
63
|
+
|
|
64
|
+
<% if Blazer.slack? %>
|
|
65
|
+
<div class="form-group">
|
|
66
|
+
<%= f.label :slack_channels %>
|
|
67
|
+
<%= f.text_field :slack_channels, placeholder: "Optional, comma separated", class: "form-control" %>
|
|
68
|
+
</div>
|
|
69
|
+
<% end %>
|
|
70
|
+
|
|
71
|
+
<p class="text-muted">Emails <%= Blazer.slack? ? "and Slack notifications " : nil %>are sent when a check starts failing, and when it starts passing again.
|
|
64
72
|
<p>
|
|
65
73
|
<% if @check.persisted? %>
|
|
66
74
|
<%= link_to "Delete", check_path(@check), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<th>Query</th>
|
|
10
10
|
<th style="width: 10%;">State</th>
|
|
11
11
|
<th style="width: 10%;">Run</th>
|
|
12
|
-
<th style="width: 20%;">
|
|
12
|
+
<th style="width: 20%;">Notify</th>
|
|
13
13
|
<th style="width: 15%;"></th>
|
|
14
14
|
</tr>
|
|
15
15
|
</thead>
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
<% check.split_emails.each do |email| %>
|
|
29
29
|
<li><%= email %></li>
|
|
30
30
|
<% end %>
|
|
31
|
+
<% check.split_slack_channels.each do |channel| %>
|
|
32
|
+
<li><%= channel %></li>
|
|
33
|
+
<% end %>
|
|
31
34
|
</ul>
|
|
32
35
|
</td>
|
|
33
36
|
<td style="text-align: right; padding: 1px;">
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<div class="pull-left" style="margin-top: 9px;">
|
|
17
17
|
<%= link_to "Back", :back %>
|
|
18
18
|
</div>
|
|
19
|
-
<a :href="dataSourcePath" target="_blank" style="margin-right: 10px;">
|
|
19
|
+
<a :href="dataSourcePath" target="_blank" style="margin-right: 10px;">Docs</a>
|
|
20
20
|
<%= f.select :data_source, Blazer.data_sources.values.select { |ds| q = @query.dup; q.data_source = ds.id; q.editable?(blazer_user) }.map { |ds| [ds.name, ds.id] }, {}, class: ("hide" if Blazer.data_sources.size <= 1), style: "width: 140px;" %>
|
|
21
21
|
<div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;">
|
|
22
22
|
<select id="table_names" style="width: 240px;" placeholder="Preview table"></select>
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
editor.focus()
|
|
174
174
|
},
|
|
175
175
|
adjustHeight: function() {
|
|
176
|
-
//
|
|
176
|
+
// https://stackoverflow.com/questions/11584061/
|
|
177
177
|
var editor = this.editor
|
|
178
178
|
var lines = editor.getSession().getScreenLength()
|
|
179
179
|
if (lines < 9) {
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<% blazer_title @data_source.name %>
|
|
2
|
+
|
|
3
|
+
<h1><%= @data_source.name %></h1>
|
|
4
|
+
|
|
5
|
+
<h2>Smart Variables</h2>
|
|
6
|
+
|
|
7
|
+
<p>Use these variable names to get a dropdown.</p>
|
|
8
|
+
|
|
9
|
+
<table class="table" style="max-width: 500px;">
|
|
10
|
+
<thead>
|
|
11
|
+
<tr>
|
|
12
|
+
<th>Variable</th>
|
|
13
|
+
</tr>
|
|
14
|
+
</thead>
|
|
15
|
+
<tbody>
|
|
16
|
+
<% @data_source.smart_variables.each do |k, _| %>
|
|
17
|
+
<tr>
|
|
18
|
+
<td><code>{<%= k %>}</code></td>
|
|
19
|
+
</tr>
|
|
20
|
+
<% end %>
|
|
21
|
+
</tbody>
|
|
22
|
+
</table>
|
|
23
|
+
|
|
24
|
+
<p>Use <code>{start_time}</code> and <code>{end_time}</code> for a date range selector. End a variable name with <code>_at</code> for a date selector.</p>
|
|
25
|
+
|
|
26
|
+
<h2>Linked Columns</h2>
|
|
27
|
+
|
|
28
|
+
<p>Use these column names to link results to other pages.</p>
|
|
29
|
+
|
|
30
|
+
<table class="table" style="max-width: 500px;">
|
|
31
|
+
<thead>
|
|
32
|
+
<tr>
|
|
33
|
+
<th style="width: 20%;">Name</th>
|
|
34
|
+
<th>URL</th>
|
|
35
|
+
</tr>
|
|
36
|
+
</thead>
|
|
37
|
+
<tbody>
|
|
38
|
+
<% @data_source.linked_columns.each do |k, v| %>
|
|
39
|
+
<tr>
|
|
40
|
+
<td><%= k %></td>
|
|
41
|
+
<td><%= v %></td>
|
|
42
|
+
</tr>
|
|
43
|
+
<% end %>
|
|
44
|
+
</tbody>
|
|
45
|
+
</table>
|
|
46
|
+
|
|
47
|
+
<p>Values that match the format of a URL will be linked automatically.</p>
|
|
48
|
+
|
|
49
|
+
<h2>Smart Columns</h2>
|
|
50
|
+
|
|
51
|
+
<p>Use these column names to show additional data.</p>
|
|
52
|
+
|
|
53
|
+
<table class="table" style="max-width: 500px;">
|
|
54
|
+
<thead>
|
|
55
|
+
<tr>
|
|
56
|
+
<th>Name</th>
|
|
57
|
+
</tr>
|
|
58
|
+
</thead>
|
|
59
|
+
<tbody>
|
|
60
|
+
<% @data_source.smart_columns.each do |k, _| %>
|
|
61
|
+
<tr>
|
|
62
|
+
<td><%= k %></td>
|
|
63
|
+
</tr>
|
|
64
|
+
<% end %>
|
|
65
|
+
</tbody>
|
|
66
|
+
</table>
|
|
67
|
+
|
|
68
|
+
<h2>Charts</h2>
|
|
69
|
+
|
|
70
|
+
<p>Use specific combinations of column types to generate charts.</p>
|
|
71
|
+
|
|
72
|
+
<table class="table" style="max-width: 500px;">
|
|
73
|
+
<thead>
|
|
74
|
+
<tr>
|
|
75
|
+
<th style="width: 20%;">Chart</th>
|
|
76
|
+
<th>Column Types</th>
|
|
77
|
+
</tr>
|
|
78
|
+
</thead>
|
|
79
|
+
<tbody>
|
|
80
|
+
<tr>
|
|
81
|
+
<td>Line</td>
|
|
82
|
+
<td>2+ columns - timestamp, numeric(s)</td>
|
|
83
|
+
</tr>
|
|
84
|
+
<tr>
|
|
85
|
+
<td>Line</td>
|
|
86
|
+
<td>3 columns - timestamp, string, numeric</td>
|
|
87
|
+
</tr>
|
|
88
|
+
<tr>
|
|
89
|
+
<td>Column</td>
|
|
90
|
+
<td>2+ columns - string, numeric(s)</td>
|
|
91
|
+
</tr>
|
|
92
|
+
<tr>
|
|
93
|
+
<td>Column</td>
|
|
94
|
+
<td>3 columns - string, string, numeric</td>
|
|
95
|
+
</tr>
|
|
96
|
+
<tr>
|
|
97
|
+
<td>Scatter</td>
|
|
98
|
+
<td>2 columns - both numeric</td>
|
|
99
|
+
</tr>
|
|
100
|
+
<tr>
|
|
101
|
+
<td>Map</td>
|
|
102
|
+
<td>
|
|
103
|
+
Named <code>latitude</code> and <code>longitude</code>, or <code>lat</code> and <code>lon</code>, or <code>lat</code> and <code>lng</code>
|
|
104
|
+
<% if !blazer_maps? %>
|
|
105
|
+
<br />
|
|
106
|
+
<strong>Needs configured</strong>
|
|
107
|
+
<% end %>
|
|
108
|
+
</td>
|
|
109
|
+
</tr>
|
|
110
|
+
</tbody>
|
|
111
|
+
</table>
|
|
112
|
+
|
|
113
|
+
<p>Use the column name <code>target</code> to draw a line for goals.</p>
|
|
114
|
+
|
|
115
|
+
<h2>Schema</h2>
|
|
116
|
+
|
|
117
|
+
<% @schema.each do |table| %>
|
|
118
|
+
<table class="table" style="max-width: 500px;">
|
|
119
|
+
<thead>
|
|
120
|
+
<tr>
|
|
121
|
+
<th colspan="2">
|
|
122
|
+
<%= table[:table] %>
|
|
123
|
+
<% if table[:schema] != "public" %>
|
|
124
|
+
<span class="text-muted" style="font-weight: normal;"><%= table[:schema] %></span>
|
|
125
|
+
<% end %>
|
|
126
|
+
</th>
|
|
127
|
+
</tr>
|
|
128
|
+
</thead>
|
|
129
|
+
<tbody>
|
|
130
|
+
<% table[:columns].each do |column| %>
|
|
131
|
+
<tr>
|
|
132
|
+
<td style="width: 60%;"><%= column[:name] %></td>
|
|
133
|
+
<td class="text-muted"><%= column[:data_type] %></td>
|
|
134
|
+
</tr>
|
|
135
|
+
<% end %>
|
|
136
|
+
</tbody>
|
|
137
|
+
</table>
|
|
138
|
+
<% end %>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
</script>
|
|
63
63
|
<% end %>
|
|
64
64
|
|
|
65
|
-
<% unless %w(mongodb
|
|
65
|
+
<% unless %w(mongodb).include?(Blazer.data_sources[@query.data_source].adapter) %>
|
|
66
66
|
<script>
|
|
67
67
|
// do not highlight really long queries
|
|
68
68
|
// this can lead to performance issues
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<%= blazer_js_var "rootPath", root_path %>
|
|
12
12
|
</script>
|
|
13
13
|
<% if blazer_maps? %>
|
|
14
|
-
<%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/
|
|
15
|
-
<%= javascript_include_tag "https://api.mapbox.com/mapbox.js/
|
|
14
|
+
<%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.css", integrity: "sha384-o8tecBIfqi9yU5yYK2Ne/9A9hlOGFV9MBvCpmemvJH1XxqOe6h8Bl4mLxMi6PgjG", crossorigin: "anonymous" %>
|
|
15
|
+
<%= javascript_include_tag "https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.js", integrity: "sha384-j81LqvtvYigFzGSUgAoFijpvoq4yGoCJSOXI9DFaUEpenR029MBE3E/X5Gr+WdO0", crossorigin: "anonymous" %>
|
|
16
16
|
<% end %>
|
|
17
17
|
<%= csrf_meta_tags %>
|
|
18
18
|
</head>
|
data/config/routes.rb
CHANGED
data/lib/blazer.rb
CHANGED
|
@@ -39,6 +39,8 @@ module Blazer
|
|
|
39
39
|
attr_accessor :images
|
|
40
40
|
attr_accessor :query_viewable
|
|
41
41
|
attr_accessor :query_editable
|
|
42
|
+
attr_accessor :override_csp
|
|
43
|
+
attr_accessor :slack_webhook_url
|
|
42
44
|
end
|
|
43
45
|
self.audit = true
|
|
44
46
|
self.user_name = :name
|
|
@@ -46,6 +48,7 @@ module Blazer
|
|
|
46
48
|
self.anomaly_checks = false
|
|
47
49
|
self.async = false
|
|
48
50
|
self.images = false
|
|
51
|
+
self.override_csp = false
|
|
49
52
|
|
|
50
53
|
TIMEOUT_MESSAGE = "Query timed out :("
|
|
51
54
|
TIMEOUT_ERRORS = [
|
|
@@ -93,20 +96,11 @@ module Blazer
|
|
|
93
96
|
|
|
94
97
|
def self.data_sources
|
|
95
98
|
@data_sources ||= begin
|
|
96
|
-
ds = Hash
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
]
|
|
101
|
-
ds.default = ds.values.first
|
|
99
|
+
ds = Hash.new { |hash, key| raise Blazer::Error, "Unknown data source: #{key}" }
|
|
100
|
+
settings["data_sources"].each do |id, s|
|
|
101
|
+
ds[id] = Blazer::DataSource.new(id, s)
|
|
102
|
+
end
|
|
102
103
|
ds
|
|
103
|
-
|
|
104
|
-
# TODO Blazer 2.0
|
|
105
|
-
# ds2 = Hash.new { |hash, key| raise Blazer::Error, "Unknown data source: #{key}" }
|
|
106
|
-
# ds.each do |k, v|
|
|
107
|
-
# ds2[k] = v
|
|
108
|
-
# end
|
|
109
|
-
# ds2
|
|
110
104
|
end
|
|
111
105
|
end
|
|
112
106
|
|
|
@@ -126,8 +120,6 @@ module Blazer
|
|
|
126
120
|
end
|
|
127
121
|
|
|
128
122
|
def self.run_check(check)
|
|
129
|
-
rows = nil
|
|
130
|
-
error = nil
|
|
131
123
|
tries = 1
|
|
132
124
|
|
|
133
125
|
ActiveSupport::Notifications.instrument("run_check.blazer", check_id: check.id, query_id: check.query.id, state_was: check.state) do |instrument|
|
|
@@ -173,10 +165,15 @@ module Blazer
|
|
|
173
165
|
|
|
174
166
|
def self.send_failing_checks
|
|
175
167
|
emails = {}
|
|
168
|
+
slack_channels = {}
|
|
169
|
+
|
|
176
170
|
Blazer::Check.includes(:query).where(state: ["failing", "error", "timed out", "disabled"]).find_each do |check|
|
|
177
171
|
check.split_emails.each do |email|
|
|
178
172
|
(emails[email] ||= []) << check
|
|
179
173
|
end
|
|
174
|
+
check.split_slack_channels.each do |channel|
|
|
175
|
+
(slack_channels[channel] ||= []) << check
|
|
176
|
+
end
|
|
180
177
|
end
|
|
181
178
|
|
|
182
179
|
emails.each do |email, checks|
|
|
@@ -184,6 +181,16 @@ module Blazer
|
|
|
184
181
|
Blazer::CheckMailer.failing_checks(email, checks).deliver_now
|
|
185
182
|
end
|
|
186
183
|
end
|
|
184
|
+
|
|
185
|
+
slack_channels.each do |channel, checks|
|
|
186
|
+
Safely.safely do
|
|
187
|
+
Blazer::SlackNotifier.failing_checks(channel, checks)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def self.slack?
|
|
193
|
+
slack_webhook_url.present?
|
|
187
194
|
end
|
|
188
195
|
|
|
189
196
|
def self.adapters
|