Explore your data with SQL. Easily create charts and dashboards, and share them with your team.
🍊 Battle-tested at Instacart
- Multiple data sources - PostgreSQL, MySQL, Redshift, and many more
- Variables - run the same queries with different values
- Checks & alerts - get emailed when bad data appears
- Audits - all queries are tracked
- Security - works with your authentication system
Add this line to your application’s Gemfile:
gem 'blazer'
Run:
rails g blazer:install
rake db:migrate
And mount the dashboard in your config/routes.rb
:
mount Blazer::Engine, at: "blazer"
For production, specify your database:
ENV["BLAZER_DATABASE_URL"] = "postgres://user:password@hostname:5432/database"
Blazer tries to protect against queries which modify data (by running each query in a transaction and rolling it back), but a safer approach is to use a read only user. See how to create one.
Be sure to set a host in config/environments/production.rb
for emails to work.
config.action_mailer.default_url_options = {host: "blazerme.herokuapp.com"}
Schedule checks to run (with cron, Heroku Scheduler, etc). The default options are every 5 minutes, 1 hour, or 1 day, which you can customize. For each of these options, set up a task to run.
rake blazer:run_checks SCHEDULE="5 minutes"
rake blazer:run_checks SCHEDULE="1 hour"
rake blazer:run_checks SCHEDULE="1 day"
You can also set up failing checks to be sent once a day (or whatever you prefer).
rake blazer:send_failing_checks
Here’s what it looks like with cron.
*/5 * * * * rake blazer:run_checks SCHEDULE="5 minutes"
0 * * * * rake blazer:run_checks SCHEDULE="1 hour"
30 7 * * * rake blazer:run_checks SCHEDULE="1 day"
0 8 * * * rake blazer:send_failing_checks
Create a user with read only permissions:
BEGIN;
CREATE ROLE blazer LOGIN PASSWORD 'secret123';
GRANT CONNECT ON DATABASE database_name TO blazer;
GRANT USAGE ON SCHEMA public TO blazer;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO blazer;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO blazer;
COMMIT;
Create a user with read only permissions:
GRANT SELECT, SHOW VIEW ON database_name.* TO blazer@’127.0.0.1′ IDENTIFIED BY ‘secret123‘;
FLUSH PRIVILEGES;
Create a user with read only permissions:
db.createUser({user: "blazer", pwd: "password", roles: ["read"]})
Also, make sure authorization is enabled when you start the server.
To protect sensitive info like password hashes and access tokens, use views. Documentation coming soon.
Don’t forget to protect the dashboard in production.
Set the following variables in your environment or an initializer.
ENV["BLAZER_USERNAME"] = "andrew"
ENV["BLAZER_PASSWORD"] = "secret"
authenticate :user, -> (user) { user.admin? } do
mount Blazer::Engine, at: "blazer"
end
Specify a before_action
method to run in blazer.yml
.
before_action: require_admin
Create queries with variables.
SELECT * FROM users WHERE gender = {gender}
Use {start_time}
and {end_time}
for time ranges. Example
SELECT * FROM ratings WHERE rated_at >= {start_time} AND rated_at <= {end_time}
Suppose you have the query:
SELECT * FROM users WHERE occupation_id = {occupation_id}
Instead of remembering each occupation’s id, users can select occupations by name.
Add a smart variable with:
smart_variables:
occupation_id: "SELECT id, name FROM occupations ORDER BY name ASC"
The first column is the value of the variable, and the second column is the label.
You can also use an array or hash for static data and enums.
smart_variables:
period: ["day", "week", "month"]
status: {0: "Active", 1: "Archived"}
Example - title column
Link results to other pages in your apps or around the web. Specify a column name and where it should link to. You can use the value of the result with {value}
.
linked_columns:
user_id: "/admin/users/{value}"
ip_address: "http://www.infosniper.net/index.php?ip_address={value}"
Example - occupation_id column
Suppose you have the query:
SELECT name, city_id FROM users
See which city the user belongs to without a join.
smart_columns:
city_id: "SELECT id, name FROM cities WHERE id IN {value}"
You can also use a hash for static data and enums.
smart_columns:
status: {0: "Active", 1: "Archived"}
Blazer can automatically cache results to improve speed. It can cache slow queries:
cache:
mode: slow
expires_in: 60 # min
slow_threshold: 15 # sec
Or it can cache all queries:
cache:
mode: all
expires_in: 60 # min
Of course, you can force a refresh at any time.
Blazer will automatically generate charts based on the types of the columns returned in your query.
Note: The order of columns matters.
There are two ways to generate line charts.
2+ columns - timestamp, numeric(s) - Example
SELECT date_trunc('week', created_at), COUNT(*) FROM users GROUP BY 1
3 columns - timestamp, string, numeric - Example
SELECT date_trunc('week', created_at), gender, COUNT(*) FROM users GROUP BY 1, 2
There are also two ways to generate column charts.
2+ columns - string, numeric(s) - Example
SELECT gender, COUNT(*) FROM users GROUP BY 1
3 columns - string, string, numeric - Example
SELECT gender, zip_code, COUNT(*) FROM users GROUP BY 1, 2
2 columns - both numeric
SELECT x, y FROM table
Columns named latitude
and longitude
or lat
and lon
or lat
and lng
- Example
SELECT name, latitude, longitude FROM cities
To enable, get an access token from Mapbox and set ENV["MAPBOX_ACCESS_TOKEN"]
.
Use the column name target
to draw a line for goals. Example
SELECT date_trunc('week', created_at), COUNT(*) AS new_users, 100000 AS target FROM users GROUP BY 1
Create a dashboard with multiple queries. Example
If the query has a chart, the chart is shown. Otherwise, you’ll see a table.
If any queries have variables, they will show up on the dashboard.
Checks give you a centralized place to see the health of your data. Example
Create a query to identify bad rows.
SELECT * FROM ratings WHERE user_id IS NULL /* all ratings should have a user */
Then create check with optional emails if you want to be notified. Emails are sent when a check starts failing, and when it starts passing again.
Anomaly detection is supported thanks to Twitter’s AnomalyDetection library.
First, install R. Then, run:
install.packages("devtools")
devtools::install_github("twitter/AnomalyDetection")
And add to config/blazer.yml
:
anomaly_checks: true
If upgrading from version 1.4 or below, also follow the upgrade instructions.
If you’re on Heroku, follow these additional instructions.
Blazer supports multiple data sources 🎉
Add additional data sources in config/blazer.yml
:
data_sources:
main:
url: <%= ENV["BLAZER_DATABASE_URL"] %>
# timeout, smart_variables, linked_columns, smart_columns
catalog:
url: <%= ENV["CATALOG_DATABASE_URL"] %>
# ...
redshift:
url: <%= ENV["REDSHIFT_DATABASE_URL"] %>
# ...
- PostgreSQL
- MySQL
- SQL Server
- Oracle
- IBM DB2 and Informix
- SQLite
- Redshift
- Presto
- MongoDB [beta]
- Elasticsearch [beta]
- Apache Drill [beta]
You can also create an adapter for any other data store.
Note: In the examples below, we recommend using environment variables for urls.
data_sources:
my_source:
url: <%= ENV["BLAZER_MY_SOURCE_URL"] %>
Add pg to your Gemfile (if it’s not there) and set:
data_sources:
my_source:
url: postgres://user:password@hostname:5432/database
Add mysql2 to your Gemfile (if it’s not there) and set:
data_sources:
my_source:
url: mysql2://user:password@hostname:3306/database
Add tiny_tds and activerecord-sqlserver-adapter to your Gemfile and set:
data_sources:
my_source:
url: sqlserver://user:password@hostname:1433/database
Use activerecord-oracle_enhanced-adapter.
Use ibm_db.
Add sqlite3 to your Gemfile and set:
data_sources:
my_source:
url: sqlite3:path/to/database.sqlite3
Add activerecord4-redshift-adapter or activerecord5-redshift-adapter to your Gemfile and set:
data_sources:
my_source:
url: redshift://user:password@hostname:5439/database
Add presto-client to your Gemfile and set:
data_sources:
my_source:
url: presto://user@hostname:8080/catalog
Add mongo to your Gemfile and set:
data_sources:
my_source:
url: mongodb://user:password@hostname:27017/database
Add elasticsearch to your Gemfile and set:
data_sources:
my_source:
adapter: elasticsearch
url: http://user:password@hostname:9200/
Set:
data_sources:
my_source:
adapter: drill
url: http://hostname:8047
Create an adapter for any data store with:
class FooAdapter < Blazer::Adapters::BaseAdapter
# code goes here
end
Blazer.register_adapter "foo", FooAdapter
See the Presto adapter for a good example. Then use:
data_sources:
my_source:
adapter: foo
url: http://user:password@hostname:9200/
Blazer supports a basic permissions model.
- Queries without a name are unlisted
- Queries whose name starts with
#
are only listed to the creator - Queries whose name starts with
*
can only be edited by the creator
Have team members who want to learn SQL? Here are a few great, free resources.
For an easy way to group by day, week, month, and more with correct time zones, check out Groupdate.
Add the R buildpack to your app.
heroku buildpacks:add --index 1 https://github.com/virtualstaticvoid/heroku-buildpack-r.git\#cedar-14
And create an init.r
with:
if (!"AnomalyDetection" %in% installed.packages()) {
install.packages("devtools")
devtools::install_github("twitter/AnomalyDetection")
}
Commit and deploy away. The first deploy may take a few minutes.
To take advantage of the anomaly detection, create a migration
rails g migration upgrade_blazer_to_1_5
with:
add_column(:blazer_checks, :check_type, :string)
add_column(:blazer_checks, :message, :text)
commit_db_transaction
Blazer::Check.reset_column_information
Blazer::Check.where(invert: true).update_all(check_type: "missing_data")
Blazer::Check.where(check_type: nil).update_all(check_type: "bad_data")
To take advantage of the latest features, create a migration
rails g migration upgrade_blazer_to_1_3
with:
add_column :blazer_dashboards, :creator_id, :integer
add_column :blazer_checks, :creator_id, :integer
add_column :blazer_checks, :invert, :boolean
add_column :blazer_checks, :schedule, :string
add_column :blazer_checks, :last_run_at, :timestamp
commit_db_transaction
Blazer::Check.update_all schedule: "1 hour"
Blazer 1.0 brings a number of new features:
- multiple data sources, including Redshift
- dashboards
- checks
To upgrade, run:
bundle update blazer
Create a migration
rails g migration upgrade_blazer_to_1_0
with:
add_column :blazer_queries, :data_source, :string
add_column :blazer_audits, :data_source, :string
create_table :blazer_dashboards do |t|
t.text :name
t.timestamps
end
create_table :blazer_dashboard_queries do |t|
t.references :dashboard
t.references :query
t.integer :position
t.timestamps
end
create_table :blazer_checks do |t|
t.references :query
t.string :state
t.text :emails
t.timestamps
end
And run:
rake db:migrate
Update config/blazer.yml
with:
# see https://github.com/ankane/blazer for more info
data_sources:
main:
url: <%= ENV["BLAZER_DATABASE_URL"] %>
# statement timeout, in seconds
# applies to PostgreSQL only
# none by default
# timeout: 15
# time to cache results, in minutes
# can greatly improve speed
# none by default
# cache: 60
# wrap queries in a transaction for safety
# not necessary if you use a read-only user
# true by default
# use_transaction: false
smart_variables:
# zone_id: "SELECT id, name FROM zones ORDER BY name ASC"
linked_columns:
# user_id: "/admin/users/{value}"
smart_columns:
# user_id: "SELECT id, name FROM users WHERE id IN {value}"
# create audits
audit: true
# change the time zone
# time_zone: "Pacific Time (US & Canada)"
# class name of the user model
# user_class: User
# method name for the current user
# user_method: current_user
# method name for the display name
# user_name: name
# email to send checks from
# from_email: [email protected]
- advanced permissions
- standalone version
- better navigation
View the changelog
Blazer uses a number of awesome open source projects, including Rails, Vue.js, jQuery, Bootstrap, Selectize, StickyTableHeaders, Stupid jQuery Table Sort, and Date Range Picker.
Demo data from MovieLens.
That’s awesome! Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
Check out the dev app to get started.