flareboard 0.0.1
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 +7 -0
- data/README.md +89 -0
- data/bin/flareboard +220 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0d2579b252fee593a40c48761c6ac965bab4b39e
|
4
|
+
data.tar.gz: a9673657a91d16531d9f40fa8555aefa8d6a7706
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d7032d8918a66d9ef8f63cee3fe859a8afb95b6034d1bc138ed0aa77b86410d0f2db1d69ae80d43e44855d98c820639e0ac82be51193de62db12186b5d3f5bc4
|
7
|
+
data.tar.gz: 5856f2bdf2487914646e2a3de877aa29f0bd32cd5458617438d9c0a66152c00236ed1826f360820563175483d06a38b2a665e4e523993f8c8a21dbb2a24b95d4
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
##What is Flareboard?
|
2
|
+
|
3
|
+
Flareboard is the way to get your [CloudFlare](http://www.cloudflare.com) stats
|
4
|
+
to display in your [StatusBoard](http://www.panic.com/statusboard). It has been
|
5
|
+
designed to be very easy to install and use. It requires no third-party gems,
|
6
|
+
and can be run on any version of ruby from 1.8.7 to 2.1.1.
|
7
|
+
|
8
|
+
Add your credentials and sites to flareboard, and it will hit the CloudFlare API
|
9
|
+
to grab your stats and convert them into the JSON that Statusboard uses for
|
10
|
+
graphing. You can drop the resulting file into a dropbox folder or host it on a
|
11
|
+
web server. Unless you are paying for a CloudFlare Pro account, your stats will
|
12
|
+
only update every 24 hours, so it's no use running flareboard more often than
|
13
|
+
that.
|
14
|
+
|
15
|
+
**Note**: For compatibility with 1.8.7. you *will* have to install the JSON gem.
|
16
|
+
Also, you have my sympathies for having to use 1.8.7.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Copy the file ```bin/flareboard``` onto your computer. Put it either in a bin
|
21
|
+
directory in your path or somewhere else. If you are using ruby 1.8.7, then
|
22
|
+
you'll have to run ```sudo gem install json``` before it will work.
|
23
|
+
|
24
|
+
## Configuration
|
25
|
+
|
26
|
+
There are three ways of configuring the script. Via the command-line arguments
|
27
|
+
documented in the previous section, via a config file (*~/.flareboard.rc*), or
|
28
|
+
by editing the script directly. In order of priority (highest to lowest), it
|
29
|
+
will use command-line options, the config file, and then the hard-coded config
|
30
|
+
hash in the script.
|
31
|
+
|
32
|
+
It is *highly* recommended to use a config file, as passing your API token on
|
33
|
+
the command-line is a security risk, and modifying the script itself will make
|
34
|
+
upgrades manual and laborious.
|
35
|
+
|
36
|
+
### :title
|
37
|
+
The title that will show up on your status board
|
38
|
+
|
39
|
+
### :token
|
40
|
+
Your Cloudflare token - available via their website at
|
41
|
+
https://www.cloudflare.com/my-account
|
42
|
+
|
43
|
+
### :email
|
44
|
+
The email you have registered with cloudflare. **NOT** your username!
|
45
|
+
|
46
|
+
### :interval
|
47
|
+
Interval Values - see https://www.cloudflare.com/docs/client-api.html for
|
48
|
+
latest.
|
49
|
+
|
50
|
+
20-40 only update once a day - it is no use polling more often than that
|
51
|
+
20 = Past 30 days
|
52
|
+
30 = Past 7 days
|
53
|
+
40 = Past day
|
54
|
+
!!! Anything higher than this requires a paid CloudFlare account !!!
|
55
|
+
!!! This also enables greater than daily updates !!!
|
56
|
+
100 = 24 hours ago
|
57
|
+
110 = 12 hours ago
|
58
|
+
120 = 6 hours ago
|
59
|
+
|
60
|
+
### :sites
|
61
|
+
Sites have a site specific title, a URL, and a color for the graph.
|
62
|
+
Colors: yellow, green, red, purple, blue, mediumGray, pink, aqua, orange, lightGray
|
63
|
+
|
64
|
+
Here is an example config file, using the same data as the example hash.
|
65
|
+
|
66
|
+
---
|
67
|
+
:token: XXXXXXX
|
68
|
+
:email: user@example.com
|
69
|
+
:sites:
|
70
|
+
- :title: 'Should I Use That In Prod'
|
71
|
+
:url: 'shouldiusethatinprod.com'
|
72
|
+
:color: 'red'
|
73
|
+
- :title: "It's Not Rocket Science"
|
74
|
+
:url: 'itsnotrocketscience.info'
|
75
|
+
:color: 'purple'
|
76
|
+
|
77
|
+
## Usage
|
78
|
+
|
79
|
+
Usage: flareboard [options]
|
80
|
+
-f, --file FILE Where to write the JSON output
|
81
|
+
Defaults to STDOUT
|
82
|
+
-t, --token TOKEN Your CloudFlare API token
|
83
|
+
-e, --email EMAIL Your CloudFlare email address
|
84
|
+
-i, --interval INTERVAL CloudFlare history interval
|
85
|
+
Defaults to 40
|
86
|
+
--title TITLE Title of the status board
|
87
|
+
Defaults to 'Cloudflare - Pageviews'
|
88
|
+
|
89
|
+
If no file is given, flareboard will write to standard out.
|
data/bin/flareboard
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# @author David Bishop
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
if RUBY_VERSION < '1.9'
|
6
|
+
require 'net/https'
|
7
|
+
end
|
8
|
+
require 'json'
|
9
|
+
require 'optparse'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
# Rather than dump out a free-form string, on errors dump out something that
|
13
|
+
# the status board app can read in and display
|
14
|
+
#
|
15
|
+
# @param error [String] Short description of the problem
|
16
|
+
# @param detail [String] Longer description or specific error code
|
17
|
+
# @return [nil]
|
18
|
+
def exit_json(error, detail)
|
19
|
+
# return the error in json form
|
20
|
+
sperror = {
|
21
|
+
'error' => {
|
22
|
+
'message' => error,
|
23
|
+
'detail' => detail
|
24
|
+
}
|
25
|
+
}
|
26
|
+
STDERR.puts error, detail
|
27
|
+
puts sperror.to_json
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
# Take the integer that CloudFlare uses and return a description in english
|
32
|
+
#
|
33
|
+
# @param interval [Integer] Integer needed by Cloudflare API
|
34
|
+
# @return [String] Description in english
|
35
|
+
def name_interval(interval)
|
36
|
+
title = {
|
37
|
+
20 => 'Last Month',
|
38
|
+
30 => 'Last Week',
|
39
|
+
40 => 'Yesterday',
|
40
|
+
100 => '24 Hours Ago',
|
41
|
+
110 => '12 Hours Ago',
|
42
|
+
120 => '6 Hours Ago'
|
43
|
+
}
|
44
|
+
|
45
|
+
# hash.fetch will return the second parameter if the key doesn't exist
|
46
|
+
title.fetch(interval, 'Invalid interval')
|
47
|
+
end
|
48
|
+
|
49
|
+
# ~~~~~ CONFIG BEGIN ~~~~~
|
50
|
+
|
51
|
+
options = {
|
52
|
+
:title => 'Cloudflare - Pageviews',
|
53
|
+
:token => 'XXXXXX',
|
54
|
+
:email => 'user@example.com',
|
55
|
+
:interval => 40,
|
56
|
+
:graph => 'bar',
|
57
|
+
:sites => [
|
58
|
+
{ :title => 'Should I Use That In Prod',
|
59
|
+
:url => 'shouldiusethatinprod.com',
|
60
|
+
:color => 'red'
|
61
|
+
},
|
62
|
+
{ :title => "It's Not Rocket Science",
|
63
|
+
:url => 'itsnotrocketscience.info',
|
64
|
+
:color => 'purple'
|
65
|
+
}
|
66
|
+
]
|
67
|
+
}
|
68
|
+
|
69
|
+
# YOU SHOULD NOT NEED TO EDIT ANYTHING BELOW HERE
|
70
|
+
# IF YOU DO, PLEASE OPEN A BUG REPORT AT http://github.com/teancom/flareboard
|
71
|
+
# ~~~~~ CONFIG END ~~~~~
|
72
|
+
|
73
|
+
# The config file
|
74
|
+
CONFIG_FILE = File.join(ENV['HOME'], '.flareboard.rc')
|
75
|
+
if File.exist? CONFIG_FILE
|
76
|
+
config_options = YAML.load_file(CONFIG_FILE)
|
77
|
+
options.merge!(config_options)
|
78
|
+
end
|
79
|
+
|
80
|
+
# The name of this program
|
81
|
+
EXE_NAME = File.basename($PROGRAM_NAME)
|
82
|
+
# @todo Add support for graph type
|
83
|
+
option_parser = OptionParser.new do |opts|
|
84
|
+
opts.on('-f FILE',
|
85
|
+
'--file',
|
86
|
+
'Where to write the JSON output',
|
87
|
+
'Defaults to STDOUT'
|
88
|
+
) do |file|
|
89
|
+
options[:file] = file
|
90
|
+
end
|
91
|
+
opts.on('-t TOKEN',
|
92
|
+
'--token',
|
93
|
+
'Your CloudFlare API token'
|
94
|
+
) do |token|
|
95
|
+
options[:token] = token
|
96
|
+
end
|
97
|
+
opts.on('-e EMAIL',
|
98
|
+
'--email',
|
99
|
+
'Your CloudFlare email address'
|
100
|
+
) do |email|
|
101
|
+
options[:email] = email
|
102
|
+
end
|
103
|
+
opts.on('-i INTERVAL',
|
104
|
+
'--interval',
|
105
|
+
Integer,
|
106
|
+
'CloudFlare history interval',
|
107
|
+
'Defaults to 40'
|
108
|
+
) do |interval|
|
109
|
+
options[:interval] = interval
|
110
|
+
end
|
111
|
+
opts.on('--title TITLE',
|
112
|
+
'Title of the status board',
|
113
|
+
"Defaults to 'Cloudflare - Pageviews'"
|
114
|
+
) do |title|
|
115
|
+
options[:title] = title
|
116
|
+
end
|
117
|
+
# opts.on('--graph GRAPH',
|
118
|
+
# 'The type of graph - bar or line',
|
119
|
+
# 'Defaults to bar'
|
120
|
+
# ) do |graph|
|
121
|
+
# options[:graph] = graph
|
122
|
+
# end
|
123
|
+
opts.on("\n")
|
124
|
+
opts.on("If no file is given, #{EXE_NAME} will write to standard out.")
|
125
|
+
end
|
126
|
+
|
127
|
+
option_parser.parse!
|
128
|
+
|
129
|
+
if options.key? :file
|
130
|
+
path = File.expand_path(options[:file])
|
131
|
+
dir = File.dirname(path)
|
132
|
+
begin
|
133
|
+
$stdout.reopen(path, 'w')
|
134
|
+
rescue Errno::ENOENT
|
135
|
+
abort "Can't write into #{dir}. Does it exist?"
|
136
|
+
rescue Errno::EACCES
|
137
|
+
abort File.writable?(dir) ? "Can't write #{path}. No permission." : "Can't write into #{dir}. No permission."
|
138
|
+
rescue Errno::EISDIR
|
139
|
+
abort 'Please pass in a file name, not a directory name.'
|
140
|
+
rescue => e
|
141
|
+
abort e.message
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# The graph hash needs to match the JSON object that StatusBoard requires
|
146
|
+
graph = {
|
147
|
+
'graph' => {
|
148
|
+
'title' => options[:title],
|
149
|
+
'type' => options[:graph],
|
150
|
+
'datasequences' => []
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
uri = URI.parse('https://www.cloudflare.com/api_json.html')
|
155
|
+
request = Net::HTTP::Post.new(uri.path)
|
156
|
+
|
157
|
+
options[:sites].each_with_index do | site, key |
|
158
|
+
request.set_form_data(
|
159
|
+
'a' => 'stats',
|
160
|
+
'tkn' => options[:token],
|
161
|
+
'email' => options[:email],
|
162
|
+
'z' => site[:url],
|
163
|
+
'interval' => options[:interval]
|
164
|
+
)
|
165
|
+
httpreq = Net::HTTP.new(uri.host, uri.port)
|
166
|
+
httpreq.use_ssl = true
|
167
|
+
if RUBY_VERSION < '1.9'
|
168
|
+
httpreq.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
169
|
+
end
|
170
|
+
|
171
|
+
response = httpreq.start do |http|
|
172
|
+
http.request(request)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Got back something other than a 2xx response code
|
176
|
+
unless response.is_a? Net::HTTPSuccess
|
177
|
+
exit_json('Problems contacting the Cloudflare server', response.msg)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Parse the JSON we got back from CloudFlare
|
181
|
+
begin
|
182
|
+
result = JSON.parse(response.body)
|
183
|
+
rescue UnparserError => e
|
184
|
+
exit_json('Unable to parse the Cloudflare JSON', e)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Figure out what sort of error we got back
|
188
|
+
errcodes = { 'E_UNAUTH' => "Couldn't authenticate: ",
|
189
|
+
'err_ts' => 'Invalid interval: ',
|
190
|
+
'err_zone_not_found' => 'Probable typo in site name: ',
|
191
|
+
'E_MAXAPI' => 'CloudFlare wants you to not hit them as much: ',
|
192
|
+
'E_INVLDINPUT' => 'Unknown problem. Congrats! This is weird: '
|
193
|
+
}
|
194
|
+
|
195
|
+
if result['result'] == 'error'
|
196
|
+
if errcodes.key? result['err_code']
|
197
|
+
exit_json(errcodes[result['err_code']] + result['msg'],
|
198
|
+
result['err_code'])
|
199
|
+
else
|
200
|
+
exit_json("Unable to retrieve the Cloudflare JSON: #{result['msg']}",
|
201
|
+
result['err_code'])
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
totalhits = result['response']['result']['objs'][0]['requestsServed']['cloudflare']
|
206
|
+
crawlerhits = result['response']['result']['objs'][0]['trafficBreakdown']['pageviews']['crawler']
|
207
|
+
|
208
|
+
graph['graph']['datasequences'][key] = {
|
209
|
+
'title' => site[:title],
|
210
|
+
'color' => site[:color],
|
211
|
+
'datapoints' => [{
|
212
|
+
'title' => name_interval(options[:interval]),
|
213
|
+
'value' => totalhits - crawlerhits
|
214
|
+
}]
|
215
|
+
}
|
216
|
+
# graph['graph']['datasequences'][key]['datapoints'][0]['title'] = 'Nudiustertian'
|
217
|
+
# graph['graph']['datasequences'][key]['datapoints'][1]['title'] = 'Yesterday'
|
218
|
+
end
|
219
|
+
|
220
|
+
puts graph.to_json
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flareboard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Bishop
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
description: |-
|
56
|
+
flareboard allows you to display your CloudFlare statistics
|
57
|
+
in the Panic Software's StatusBoard app
|
58
|
+
email: david at gnuconsulting dotcom
|
59
|
+
executables:
|
60
|
+
- flareboard
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- README.md
|
65
|
+
- bin/flareboard
|
66
|
+
homepage: http://github.com/teancom/flareboard
|
67
|
+
licenses:
|
68
|
+
- ISC
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: flareboard
|
86
|
+
rubygems_version: 2.2.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: flareboard gets your cloudflare stats into statusboard
|
90
|
+
test_files: []
|