fluentd-server 0.1.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 +7 -0
- data/.env +5 -0
- data/.gitignore +17 -0
- data/.travis.yml +5 -0
- data/API.md +21 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +9 -0
- data/Procfile +1 -0
- data/README.md +127 -0
- data/Rakefile +26 -0
- data/bench/bench.rb +83 -0
- data/bench/result.md +17 -0
- data/bin/fluentd-server +7 -0
- data/config.ru +15 -0
- data/config/unicorn.conf +20 -0
- data/db/migrate/20140512203133_create_posts.rb +14 -0
- data/db/schema.rb +25 -0
- data/fluentd-server.gemspec +43 -0
- data/lib/fluentd_server.rb +1 -0
- data/lib/fluentd_server/cli.rb +64 -0
- data/lib/fluentd_server/config.rb +27 -0
- data/lib/fluentd_server/decorator.rb +21 -0
- data/lib/fluentd_server/environments.rb +34 -0
- data/lib/fluentd_server/logger.rb +90 -0
- data/lib/fluentd_server/model.rb +10 -0
- data/lib/fluentd_server/version.rb +3 -0
- data/lib/fluentd_server/web.rb +101 -0
- data/lib/fluentd_server/web_helper.rb +91 -0
- data/public/css/bootstrap.min.css +7 -0
- data/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/js/bootstrap.min.js +7 -0
- data/public/js/jquery-1.10.2.min.js +6 -0
- data/public/js/jquery-1.10.2.min.map +0 -0
- data/public/js/jquery.storageapi.min.js +2 -0
- data/spec/api_spec.rb +42 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/web_helper_spec.rb +27 -0
- data/spec/web_spec.rb +55 -0
- data/views/_navbar.slim +15 -0
- data/views/layout.slim +22 -0
- data/views/posts/create.slim +19 -0
- data/views/posts/edit.slim +23 -0
- data/views/posts/index.slim +9 -0
- metadata +363 -0
@@ -0,0 +1 @@
|
|
1
|
+
require "fluentd_server/version"
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "dotenv"
|
3
|
+
require "thor"
|
4
|
+
require 'fluentd_server'
|
5
|
+
|
6
|
+
class FluentdServer::CLI < Thor
|
7
|
+
BASE_DIR = File.join(Dir.pwd, "fluentd-server")
|
8
|
+
DATA_DIR = File.join(BASE_DIR, "data")
|
9
|
+
LOG_DIR = File.join(BASE_DIR, "log")
|
10
|
+
LOG_FILE = File.join(LOG_DIR, "application.log")
|
11
|
+
ENV_FILE = File.join(BASE_DIR, ".env")
|
12
|
+
PROCFILE = File.join(BASE_DIR, "Procfile")
|
13
|
+
CONFIGRU_FILE = File.join(BASE_DIR, "config.ru")
|
14
|
+
DB_DIR = File.join(BASE_DIR, "db")
|
15
|
+
CONFIG_DIR= File.join(BASE_DIR, "config")
|
16
|
+
|
17
|
+
DEFAULT_DOTENV =<<-EOS
|
18
|
+
PORT=5126
|
19
|
+
HOST=0.0.0.0
|
20
|
+
DATABASE_URL=sqlite3:#{DATA_DIR}/fluentd_server.db
|
21
|
+
LOG_PATH=#{LOG_FILE}
|
22
|
+
LOG_LEVEL=warn
|
23
|
+
EOS
|
24
|
+
|
25
|
+
DEFAULT_PROCFILE =<<-EOS
|
26
|
+
web: unicorn -E production -p $PORT -o $HOST -c config/unicorn.conf
|
27
|
+
EOS
|
28
|
+
|
29
|
+
default_command :start
|
30
|
+
|
31
|
+
desc "new", "Creates fluentd-server resource directory"
|
32
|
+
def new
|
33
|
+
FileUtils.mkdir_p(LOG_DIR)
|
34
|
+
File.write ENV_FILE, DEFAULT_DOTENV
|
35
|
+
File.write PROCFILE, DEFAULT_PROCFILE
|
36
|
+
FileUtils.cp(File.expand_path("../../../config.ru", __FILE__), CONFIGRU_FILE)
|
37
|
+
FileUtils.cp_r(File.expand_path("../../../db", __FILE__), DB_DIR)
|
38
|
+
FileUtils.cp_r(File.expand_path("../../../config", __FILE__), CONFIG_DIR)
|
39
|
+
puts 'fluentd-server new finished.'
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "init", "Creates database schema"
|
43
|
+
def init
|
44
|
+
require 'fluentd_server/environments'
|
45
|
+
require 'rake'
|
46
|
+
require 'sinatra/activerecord/rake'
|
47
|
+
Rake::Task['db:migrate'].invoke
|
48
|
+
puts 'fluentd-server init finished.'
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "start", "Sartup fluentd_server"
|
52
|
+
def start
|
53
|
+
Dotenv.load
|
54
|
+
require "foreman/cli"
|
55
|
+
Foreman::CLI.new.invoke(:start, [], {})
|
56
|
+
end
|
57
|
+
|
58
|
+
no_tasks do
|
59
|
+
def abort(msg)
|
60
|
+
$stderr.puts msg
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/activerecord'
|
3
|
+
require 'fluentd_server'
|
4
|
+
require 'dotenv'
|
5
|
+
Dotenv.load
|
6
|
+
|
7
|
+
module FluentdServer::Config
|
8
|
+
def self.database_url
|
9
|
+
ENV.fetch('DATABASE_URL', 'sqlite3:data/fluentd_server.db')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.log_path
|
13
|
+
ENV.fetch('LOG_PATH', 'STDOUT')
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.log_level
|
17
|
+
ENV.fetch('LOG_LEVEL', 'debug')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.log_shift_age
|
21
|
+
ENV.fetch('LOG_SHIFT_AGE', '0')
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.log_shift_size
|
25
|
+
ENV.fetch('LOG_SHIFT_SIZE', '1048576')
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sinatra/decorator'
|
2
|
+
|
3
|
+
class PostDecorator < Sinatra::Decorator::Base
|
4
|
+
include Rack::Utils
|
5
|
+
|
6
|
+
def success_message
|
7
|
+
'Success!'
|
8
|
+
end
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
message = 'Failure! '
|
12
|
+
message += self.errors.map {|key, msg| escape_html("`#{key}` #{msg}") }.join('. ')
|
13
|
+
message
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_body(locals)
|
17
|
+
namespace = OpenStruct.new(locals)
|
18
|
+
ERB.new(self.body, nil, "-").result(namespace.instance_eval { binding })
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/activerecord'
|
3
|
+
require 'fluentd_server/config'
|
4
|
+
require 'fluentd_server/logger'
|
5
|
+
|
6
|
+
configure do
|
7
|
+
set :show_exceptions, true
|
8
|
+
ActiveRecord::Base.logger = FluentdServer.logger
|
9
|
+
I18n.enforce_available_locales = false
|
10
|
+
end
|
11
|
+
|
12
|
+
configure :production, :development do
|
13
|
+
if FluentdServer::Config.database_url.start_with?('sqlite')
|
14
|
+
set :database, FluentdServer::Config.database_url
|
15
|
+
else
|
16
|
+
# DATABASE_URL => "postgres://randuser:randpass@randhost:randport/randdb" on heroku
|
17
|
+
db = URI.parse(FluentdServer::Config.database_url)
|
18
|
+
ActiveRecord::Base.establish_connection(
|
19
|
+
:adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
|
20
|
+
:host => db.host,
|
21
|
+
:username => db.user,
|
22
|
+
:password => db.password,
|
23
|
+
:database => db.path[1..-1],
|
24
|
+
:encoding => 'utf8'
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
configure :test do
|
30
|
+
ActiveRecord::Base.establish_connection(
|
31
|
+
:adapter => 'sqlite3',
|
32
|
+
:database => ':memory'
|
33
|
+
)
|
34
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'fluentd_server'
|
3
|
+
require "fluentd_server/config"
|
4
|
+
|
5
|
+
module FluentdServer
|
6
|
+
module Logger
|
7
|
+
def self.included(klass)
|
8
|
+
# To define logger *class* method
|
9
|
+
klass.extend(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
# for test
|
13
|
+
def logger=(logger)
|
14
|
+
FluentdServer.logger = logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def logger
|
18
|
+
FluentdServer.logger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# for test
|
23
|
+
def self.logger=(logger)
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.logger
|
28
|
+
return @logger if @logger
|
29
|
+
|
30
|
+
log_path = FluentdServer::Logger::Config.log_path
|
31
|
+
log_level = FluentdServer::Logger::Config.log_level
|
32
|
+
# NOTE: Please note that ruby 2.0.0's Logger has a problem on log rotation.
|
33
|
+
# Update to ruby 2.1.0. See https://github.com/ruby/ruby/pull/428 for details.
|
34
|
+
log_shift_age = FluentdServer::Logger::Config.log_shift_age
|
35
|
+
log_shift_size = FluentdServer::Logger::Config.log_shift_size
|
36
|
+
@logger = ::Logger.new(log_path, log_shift_age, log_shift_size)
|
37
|
+
@logger.level = log_level
|
38
|
+
@logger
|
39
|
+
end
|
40
|
+
|
41
|
+
class Logger::Config
|
42
|
+
def self.log_path(log_path = FluentdServer::Config.log_path)
|
43
|
+
case log_path
|
44
|
+
when 'STDOUT'
|
45
|
+
$stdout
|
46
|
+
when 'STDERR'
|
47
|
+
$stderr
|
48
|
+
else
|
49
|
+
log_path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.log_level(log_level = FluentdServer::Config.log_level)
|
54
|
+
case log_level
|
55
|
+
when 'debug'
|
56
|
+
::Logger::DEBUG
|
57
|
+
when 'info'
|
58
|
+
::Logger::INFO
|
59
|
+
when 'warn'
|
60
|
+
::Logger::WARN
|
61
|
+
when 'error'
|
62
|
+
::Logger::ERROR
|
63
|
+
when 'fatal'
|
64
|
+
::Logger::FATAL
|
65
|
+
else
|
66
|
+
raise ArgumentError, "invalid log_level #{log_level}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.log_shift_age(log_shift_age = FluentdServer::Config.log_shift_age)
|
71
|
+
case log_shift_age
|
72
|
+
when /\d+/
|
73
|
+
log_shift_age.to_i
|
74
|
+
when 'daily'
|
75
|
+
log_shift_age
|
76
|
+
when 'weekly'
|
77
|
+
log_shift_age
|
78
|
+
when 'monthly'
|
79
|
+
log_shift_age
|
80
|
+
else
|
81
|
+
raise ArgumentError, "invalid log_shift_age #{log_shift_age}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.log_shift_size(log_shift_size = FluentdServer::Config.log_shift_size)
|
86
|
+
log_shift_size.to_i
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/flash'
|
3
|
+
require 'sinatra/redirect_with_flash'
|
4
|
+
require 'slim'
|
5
|
+
|
6
|
+
require 'fluentd_server'
|
7
|
+
require 'fluentd_server/config'
|
8
|
+
require 'fluentd_server/environments'
|
9
|
+
require 'fluentd_server/model'
|
10
|
+
require 'fluentd_server/decorator'
|
11
|
+
require 'fluentd_server/logger'
|
12
|
+
require 'fluentd_server/web_helper'
|
13
|
+
|
14
|
+
class FluentdServer::Web < Sinatra::Base
|
15
|
+
include FluentdServer::Logger
|
16
|
+
helpers FluentdServer::WebHelper
|
17
|
+
|
18
|
+
set :dump_errors, true
|
19
|
+
set :public_folder, File.join(__dir__, '..', '..', 'public')
|
20
|
+
set :views, File.join(__dir__, '..', '..', 'views')
|
21
|
+
|
22
|
+
enable :sessions
|
23
|
+
register Sinatra::Flash
|
24
|
+
helpers Sinatra::RedirectWithFlash
|
25
|
+
register Sinatra::ActiveRecordExtension
|
26
|
+
|
27
|
+
# get ALL posts
|
28
|
+
get "/" do
|
29
|
+
@posts = Post.order("name ASC")
|
30
|
+
slim :"posts/index"
|
31
|
+
end
|
32
|
+
|
33
|
+
# create new post
|
34
|
+
get "/posts/create" do
|
35
|
+
@tab = 'create'
|
36
|
+
@title = 'Create'
|
37
|
+
@post = Post.new
|
38
|
+
slim :"posts/create"
|
39
|
+
end
|
40
|
+
|
41
|
+
post "/posts" do
|
42
|
+
@post = Post.new(params[:post])
|
43
|
+
if @post.save
|
44
|
+
redirect "posts/#{@post.id}/edit", :notice => @post.decorate.success_message
|
45
|
+
else
|
46
|
+
redirect "posts/create", :error => @post.decorate.error_message
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# edit post
|
51
|
+
get "/posts/:id/edit" do
|
52
|
+
@title = 'Edit'
|
53
|
+
@post = Post.find(params[:id])
|
54
|
+
return 404 unless @post
|
55
|
+
slim :"posts/edit"
|
56
|
+
end
|
57
|
+
|
58
|
+
post "/posts/:id" do
|
59
|
+
@post = Post.find(params[:id])
|
60
|
+
return 404 unless @post
|
61
|
+
if @post.update(params[:post])
|
62
|
+
redirect "/posts/#{@post.id}/edit", :notice => @post.decorate.success_message
|
63
|
+
else
|
64
|
+
redirect "/posts/#{@post.id}/edit", :error => @post.decorate.error_message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# delete post
|
69
|
+
get "/posts/:name/delete" do
|
70
|
+
@post = Post.find_by(name: params[:name])
|
71
|
+
if @post.destroy
|
72
|
+
redirect "/", :notice => @post.decorate.success_message
|
73
|
+
else
|
74
|
+
redirect "/", :error => @post.decorate.error_message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# get ALL posts in json
|
79
|
+
get "/json/list" do
|
80
|
+
@posts = Post.order("id ASC")
|
81
|
+
content_type :json
|
82
|
+
@posts.to_json
|
83
|
+
end
|
84
|
+
|
85
|
+
# get post in json
|
86
|
+
get "/json/:name" do
|
87
|
+
@post = Post.find_by(name: params[:name])
|
88
|
+
return 404 unless @post
|
89
|
+
content_type :json
|
90
|
+
@post.to_json
|
91
|
+
end
|
92
|
+
|
93
|
+
# render api
|
94
|
+
get "/api/:name" do
|
95
|
+
@post = Post.find_by(name: params[:name])
|
96
|
+
return 404 unless @post
|
97
|
+
query_params = parse_query(request.query_string)
|
98
|
+
content_type :text
|
99
|
+
@post.decorate.render_body(query_params)
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'fluentd_server'
|
3
|
+
|
4
|
+
module FluentdServer::WebHelper
|
5
|
+
include Rack::Utils
|
6
|
+
alias_method :h, :escape_html
|
7
|
+
|
8
|
+
# override RackUtil.parse_query
|
9
|
+
# @param qs query string
|
10
|
+
# @param d delimiter
|
11
|
+
# @return
|
12
|
+
def parse_query(qs, d=nil)
|
13
|
+
params = {}
|
14
|
+
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
15
|
+
k, v = p.split('=', 2).map { |x| unescape(x) }
|
16
|
+
if k.ends_with?('[]')
|
17
|
+
k1 = k[0..-3]
|
18
|
+
if params[k1] and params[k1].class == Array
|
19
|
+
params[k1] << v
|
20
|
+
else
|
21
|
+
params[k1] = [v]
|
22
|
+
end
|
23
|
+
elsif k.ends_with?(']') and md = k.match(/^([^\[]+)\[([^\]]+)\]$/)
|
24
|
+
k1, k2 = md[1], md[2]
|
25
|
+
if params[k1] and params[k1].class == Hash
|
26
|
+
params[k1][k2] = v
|
27
|
+
else
|
28
|
+
params[k1] = { k2 => v }
|
29
|
+
end
|
30
|
+
else
|
31
|
+
params[k] = v
|
32
|
+
end
|
33
|
+
end
|
34
|
+
params
|
35
|
+
end
|
36
|
+
|
37
|
+
def url_for(url_fragment, mode=nil, options = nil)
|
38
|
+
if mode.is_a? Hash
|
39
|
+
options = mode
|
40
|
+
mode = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
if mode.nil?
|
44
|
+
mode = :path_only
|
45
|
+
end
|
46
|
+
|
47
|
+
mode = mode.to_sym unless mode.is_a? Symbol
|
48
|
+
optstring = nil
|
49
|
+
|
50
|
+
if options.is_a? Hash
|
51
|
+
optstring = '?' + options.map { |k,v| "#{k}=#{URI.escape(v.to_s, /[^#{URI::PATTERN::UNRESERVED}]/)}" }.join('&')
|
52
|
+
end
|
53
|
+
|
54
|
+
case mode
|
55
|
+
when :path_only
|
56
|
+
base = request.script_name
|
57
|
+
when :full
|
58
|
+
scheme = request.scheme
|
59
|
+
if (scheme == 'http' && request.port == 80 ||
|
60
|
+
scheme == 'https' && request.port == 443)
|
61
|
+
port = ""
|
62
|
+
else
|
63
|
+
port = ":#{request.port}"
|
64
|
+
end
|
65
|
+
base = "#{scheme}://#{request.host}#{port}#{request.script_name}"
|
66
|
+
else
|
67
|
+
raise TypeError, "Unknown url_for mode #{mode.inspect}"
|
68
|
+
end
|
69
|
+
"#{base}#{url_fragment}#{optstring}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def escape_url(str)
|
73
|
+
CGI.escape(str)
|
74
|
+
end
|
75
|
+
|
76
|
+
def title
|
77
|
+
@title || 'Welcome'
|
78
|
+
end
|
79
|
+
|
80
|
+
def tab
|
81
|
+
@tab || 'welcome'
|
82
|
+
end
|
83
|
+
|
84
|
+
def active(_tab)
|
85
|
+
if tab == _tab
|
86
|
+
'active'
|
87
|
+
else
|
88
|
+
''
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|