logman 0.0.2 → 0.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +60 -13
- data/config.ru +2 -5
- data/database.yaml +14 -0
- data/lib/console/auth.rb +3 -3
- data/lib/console/base.rb +2 -2
- data/lib/console/bucket_api.rb +1 -1
- data/lib/console/lib/query_builder.rb +51 -0
- data/lib/console/log_api.rb +14 -9
- data/lib/console/static/app/bucket/add_edit.html +2 -2
- data/lib/console/static/app/bucket/bucket.js +18 -2
- data/lib/console/static/app/bucket/logs.html +39 -2
- data/lib/console/static/css/logman.css +9 -0
- data/lib/console/user_api.rb +1 -1
- data/lib/console/web_console.rb +1 -1
- data/lib/logman.rb +16 -0
- data/lib/logman/server.rb +1 -1
- data/lib/logman/system.rb +24 -33
- data/lib/logman/version.rb +2 -2
- data/lib/models/bucket.rb +33 -14
- data/lib/models/log.rb +36 -22
- data/lib/models/user.rb +17 -10
- data/lib/modules/log_writer.rb +5 -4
- data/logman.gemspec +5 -5
- metadata +29 -28
- data/lib/modules/secure_password.rb +0 -122
data/README.md
CHANGED
@@ -1,40 +1,85 @@
|
|
1
1
|
# Logman
|
2
2
|
|
3
|
-
Logman is Web Console/API for gathering logs from various sources and analyzing them.
|
3
|
+
Logman is Web Console/API for gathering logs from various sources and analyzing them.
|
4
|
+
Logs are saved to mongo database.
|
5
|
+
|
6
|
+
![](https://dl.dropboxusercontent.com/u/39131387/logman-c.png)
|
4
7
|
|
5
8
|
## Installation
|
6
9
|
|
7
10
|
Add this line to your application's Gemfile:
|
8
11
|
|
9
|
-
gem 'logman'
|
12
|
+
gem 'logman', :git=>'git://github.com/saicoder/logman.git'
|
10
13
|
|
11
14
|
And then execute:
|
12
15
|
|
13
16
|
$ bundle
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
$ gem install logman
|
18
|
+
Version of logman at Rubygems.org currently don't have dependencies defined, so best way to install it is over git
|
18
19
|
|
19
20
|
## Usage
|
20
21
|
|
22
|
+
Create databse configuration file `database.yaml` with mongo connection settings:
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
development:
|
26
|
+
sessions:
|
27
|
+
default:
|
28
|
+
database: logman
|
29
|
+
hosts:
|
30
|
+
- localhost:27017
|
31
|
+
|
32
|
+
production: #connection for Heroku and MongoHQ
|
33
|
+
sessions:
|
34
|
+
default:
|
35
|
+
uri: <%= ENV['MONGOHQ_URL'] %>
|
36
|
+
options:
|
37
|
+
skip_version_check: true
|
38
|
+
safe: true
|
39
|
+
```
|
40
|
+
|
21
41
|
Create rackup file `config.ru` with content:
|
22
42
|
|
23
43
|
```ruby
|
24
44
|
require 'logman'
|
25
45
|
|
26
|
-
Logman.configure
|
27
|
-
config.database_uri = 'mongodb://localhost/logman'
|
28
|
-
|
29
|
-
config.log_writer = Logman::LogWriter
|
30
|
-
config.web_console = Logman::WebConsole
|
31
|
-
end
|
46
|
+
Logman.configure
|
32
47
|
|
33
48
|
run Logman::Server
|
34
|
-
|
35
49
|
```
|
36
50
|
|
37
|
-
Execute `rackup
|
51
|
+
Execute `rackup config.ru` command
|
52
|
+
|
53
|
+
## How to use it
|
54
|
+
|
55
|
+
Open console in web browser and create your account then create Bucket for your server or web app.
|
56
|
+
Bucket is space for writing logs. Every bucket is basically mongo collection.
|
57
|
+
To send logs to bucket you need bucket token.
|
58
|
+
|
59
|
+
If you want to capture logs from Rails application you can use [Rails Logman](https://github.com/saicoder/logman_rails) gem.
|
60
|
+
|
61
|
+
To send logs manually make POST request to `http://logman_host:port/api/write?key=bucket_token` with JSON message in format:
|
62
|
+
|
63
|
+
```javascript
|
64
|
+
{
|
65
|
+
|
66
|
+
log_type: 1, //type of log: 1-error, 2-success, 3-warning,4-info
|
67
|
+
message: 'Err...', //log message
|
68
|
+
|
69
|
+
//Optional parameters
|
70
|
+
data: { //additional data
|
71
|
+
innerException: {message:'...'}
|
72
|
+
},
|
73
|
+
datetime: '1-1-2013 10:00', //time when error occurred on server
|
74
|
+
data_type: '.net exception', //not used for now, but indicates 'data' field format
|
75
|
+
|
76
|
+
sources: [{ //Name and IP of machine that generated an error,
|
77
|
+
name: 'my server', //if logman Proxy is used, it will append his hostname and ip
|
78
|
+
ip_address: '234.124.156.123'
|
79
|
+
}]
|
80
|
+
}
|
81
|
+
|
82
|
+
```
|
38
83
|
|
39
84
|
## Contributing
|
40
85
|
|
@@ -43,3 +88,5 @@ Execute `rackup -p 3000`
|
|
43
88
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
89
|
4. Push to the branch (`git push origin my-new-feature`)
|
45
90
|
5. Create new Pull Request
|
91
|
+
|
92
|
+
|
data/config.ru
CHANGED
data/database.yaml
ADDED
data/lib/console/auth.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
class Logman
|
3
3
|
class Auth < ConsoleBase
|
4
4
|
get '/login' do
|
5
5
|
erb :login, locals:{ :invalid=> false, :register=> (User.count==0) }
|
@@ -20,8 +20,8 @@ module Logman
|
|
20
20
|
end
|
21
21
|
|
22
22
|
#login routine
|
23
|
-
user = User.
|
24
|
-
|
23
|
+
user = User.where(:email=>params[:email]).first
|
24
|
+
|
25
25
|
if user.nil? || user.authenticate(params[:password]).blank?
|
26
26
|
erb :login, locals:{ :invalid=> true, :register=>false }
|
27
27
|
else
|
data/lib/console/base.rb
CHANGED
data/lib/console/bucket_api.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# Sample query
|
4
|
+
# created_at > 5, type="some type"
|
5
|
+
class Logman
|
6
|
+
class QueryBuilder
|
7
|
+
attr_accessor :con
|
8
|
+
|
9
|
+
def initialize(con)
|
10
|
+
@con = con
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def execute(param)
|
15
|
+
str = URI.decode(param)
|
16
|
+
obj = JSON.parse(str)
|
17
|
+
|
18
|
+
obj.each do |q|
|
19
|
+
build_concern(q)
|
20
|
+
end
|
21
|
+
|
22
|
+
@con
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_concern(q)
|
28
|
+
return if q['property'].blank? || q['operator'].blank?
|
29
|
+
q['property'] = '_id' if q['property'] == 'id'
|
30
|
+
|
31
|
+
|
32
|
+
@con = @con.where(q['property'].to_sym => q['value']) if q['operator'] == '='
|
33
|
+
@con = @con.where(q['property'].to_sym => Regexp.compile(".*#{q['value']}.*")) if q['operator'] == '~'
|
34
|
+
|
35
|
+
|
36
|
+
operator_map = {
|
37
|
+
'<'=> "$lt",
|
38
|
+
'<='=> "$lte",
|
39
|
+
'>'=> "$gt",
|
40
|
+
'>='=> "$gte"
|
41
|
+
}
|
42
|
+
|
43
|
+
oper = operator_map[q['operator']]
|
44
|
+
if oper
|
45
|
+
@con = @con.selector[q['property']] = {oper => q['value']}
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/console/log_api.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
class Logman
|
2
2
|
class LogAPI < ConsoleBase
|
3
3
|
|
4
4
|
get '/api/buckets/:id/logs',:auth=>:user do
|
@@ -8,20 +8,25 @@ module Logman
|
|
8
8
|
status 404
|
9
9
|
else
|
10
10
|
page = params[:page] || 1
|
11
|
-
|
12
|
-
pagination={
|
13
|
-
:order => :created_at.desc,
|
14
|
-
:per_page => params[:per_page] || 10,
|
15
|
-
:page => page
|
16
|
-
}
|
11
|
+
per_page = params[:per_page] || 10
|
17
12
|
|
13
|
+
page = page.to_i
|
14
|
+
per_page = per_page.to_i
|
18
15
|
|
19
|
-
data = bucket.logs.
|
16
|
+
data = bucket.logs.order_by(:_id.desc)
|
17
|
+
|
18
|
+
query = QueryBuilder.new(data)
|
19
|
+
data = query.execute(params[:query])
|
20
|
+
|
21
|
+
|
22
|
+
#paginate
|
23
|
+
total_count = data.count
|
24
|
+
data = data.skip((page-1)*per_page).take(per_page)
|
20
25
|
|
21
26
|
res ={
|
22
27
|
:page => page,
|
23
28
|
:items => data,
|
24
|
-
:total_items =>
|
29
|
+
:total_items => total_count,
|
25
30
|
}
|
26
31
|
|
27
32
|
json res
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<form role="form" ng-submit="saveCreate()">
|
8
8
|
<div class="form-group">
|
9
9
|
<label for="exampleInputEmail1">Bucket Name</label>
|
10
|
-
<input type="text" required ng-model="bucket.name" class="form-control" placeholder="Bucket name">
|
10
|
+
<input ng-readonly="bucket.id" type="text" required ng-model="bucket.name" class="form-control" placeholder="Bucket name">
|
11
11
|
</div>
|
12
12
|
|
13
13
|
<div class="form-group">
|
@@ -32,7 +32,7 @@
|
|
32
32
|
</div>
|
33
33
|
|
34
34
|
<button type="submit" class="btn btn-default">Save</button>
|
35
|
-
<button type="button" ng-click="destroyBucket()" class="btn btn-danger">Destroy</button>
|
35
|
+
<button ng-show="bucket.id!=null" type="button" ng-click="destroyBucket()" class="btn btn-danger">Destroy</button>
|
36
36
|
</form>
|
37
37
|
</div>
|
38
38
|
</div>
|
@@ -84,10 +84,26 @@ var BucketAddEditCtl = function($scope, $bucket, $routeParams, $user,$location){
|
|
84
84
|
|
85
85
|
var LogsCtl = function($scope, $resource, $routeParams,$bucket,$modal){
|
86
86
|
$scope.bucket = $bucket.Bucket.get({id: $routeParams.id});
|
87
|
+
$scope.criterias = [{}]
|
87
88
|
|
89
|
+
$scope.removeCriteria = function(c){
|
90
|
+
var i = $scope.criterias.indexOf(c);
|
91
|
+
if(i>-1) $scope.criterias.splice(i,1);
|
92
|
+
}
|
93
|
+
|
94
|
+
|
88
95
|
$scope.loadLogs = function(page){
|
89
|
-
|
90
|
-
|
96
|
+
if(page)$scope.active_page = page;
|
97
|
+
else page = $scope.active_page;
|
98
|
+
|
99
|
+
var queryData = JSON.stringify($scope.criterias)
|
100
|
+
queryData = encodeURIComponent(queryData);
|
101
|
+
|
102
|
+
$scope.logs = $resource('/api/buckets/:bucket_id/logs').get({
|
103
|
+
bucket_id: $routeParams.id,
|
104
|
+
page: page,
|
105
|
+
query:queryData
|
106
|
+
});
|
91
107
|
}
|
92
108
|
|
93
109
|
|
@@ -1,6 +1,43 @@
|
|
1
1
|
<div ng-controller="LogsCtl">
|
2
|
-
<h3>
|
2
|
+
<h3>
|
3
|
+
<i class="fa fa-list"></i> {{bucket.name}}
|
4
|
+
<button type="button" ng-click="query_view=!query_view" class="btn btn-default pull-right">
|
5
|
+
<i class="fa fa-filter"></i> Query
|
6
|
+
</button>
|
7
|
+
</h3>
|
3
8
|
<hr>
|
9
|
+
|
10
|
+
<div ng-show="query_view" class="panel panel-info">
|
11
|
+
<div class="panel-body">
|
12
|
+
|
13
|
+
<div class="row criteria-item" ng-repeat="c in criterias">
|
14
|
+
<div class="col-lg-4">
|
15
|
+
<input type="text" ng-model="c.property" placeholder="property" class="form-control"/>
|
16
|
+
</div>
|
17
|
+
<div class="col-lg-1">
|
18
|
+
<select class="form-control" ng-model="c.operator">
|
19
|
+
<option value="=">=</option>
|
20
|
+
<option value=">">></option>
|
21
|
+
<option value="<"><</option>
|
22
|
+
<option value=">=">>=</option>
|
23
|
+
<option value="<="><=</option>
|
24
|
+
<option value="~">~ contains</option>
|
25
|
+
</select>
|
26
|
+
</div>
|
27
|
+
<div class="col-lg-5">
|
28
|
+
<input type="text" ng-model="c.value" placeholder="value" class="form-control"/>
|
29
|
+
</div>
|
30
|
+
<div class="col-lg-1">
|
31
|
+
<button ng-click="removeCriteria(c)" class="btn btn-danger"> <i class="fa fa-minus"></i> </button>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<br>
|
36
|
+
<button ng-click="criterias.push({})" class="btn btn-default"> <i class="fa fa-plus"></i></button>
|
37
|
+
<button ng-click="loadLogs()" class="btn btn-info"> <i class="fa fa-bolt"></i> Execute </button>
|
38
|
+
|
39
|
+
</div>
|
40
|
+
</div>
|
4
41
|
|
5
42
|
<blockquote class="log-entry log-entry-type{{l.log_type}}" ng-repeat="l in logs.items">
|
6
43
|
<div class="row" ng-click="show(l)">
|
@@ -19,5 +56,5 @@
|
|
19
56
|
<p><a href="#/api_guide" class="btn btn-primary btn-lg" role="button">Learn more</a></p>
|
20
57
|
</div>
|
21
58
|
|
22
|
-
<pagination ng-show="logs.items.length != 0" total-items="logs.total_items" on-select-page="loadLogs(page)" page="logs.page" class="pagination-sm"></pagination>
|
59
|
+
<pagination max-size="15" boundary-links="true" ng-show="logs.items.length != 0" total-items="logs.total_items" on-select-page="loadLogs(page)" page="logs.page" class="pagination-sm"></pagination>
|
23
60
|
</div>
|
data/lib/console/user_api.rb
CHANGED
data/lib/console/web_console.rb
CHANGED
@@ -5,7 +5,7 @@ require File.dirname(__FILE__) + '/user_api'
|
|
5
5
|
require File.dirname(__FILE__) + '/bucket_api'
|
6
6
|
require File.dirname(__FILE__) + '/log_api'
|
7
7
|
|
8
|
-
|
8
|
+
class Logman
|
9
9
|
class WebConsole < ConsoleBase
|
10
10
|
set :public_folder, File.dirname(__FILE__) + '/static'
|
11
11
|
set :views, File.dirname(__FILE__) + '/views'
|
data/lib/logman.rb
CHANGED
@@ -1,3 +1,19 @@
|
|
1
1
|
require "logman/version"
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'sinatra'
|
5
|
+
require "sinatra/json"
|
6
|
+
|
7
|
+
# models
|
8
|
+
require 'console/lib/query_builder'
|
9
|
+
require 'models/user'
|
10
|
+
require 'models/bucket'
|
11
|
+
require 'models/log'
|
12
|
+
|
13
|
+
# modules
|
14
|
+
require 'modules/log_writer'
|
15
|
+
require 'console/web_console'
|
16
|
+
|
17
|
+
|
2
18
|
require "logman/system"
|
3
19
|
|
data/lib/logman/server.rb
CHANGED
data/lib/logman/system.rb
CHANGED
@@ -1,43 +1,27 @@
|
|
1
|
-
require 'mongo_mapper'
|
2
|
-
require 'sinatra'
|
3
|
-
require "sinatra/json"
|
4
1
|
|
5
|
-
require File.dirname(__FILE__) +'/../modules/secure_password'
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
require File.dirname(__FILE__) + '/../models/log'
|
11
|
-
|
12
|
-
# modules
|
13
|
-
require File.dirname(__FILE__) + '/../modules/log_writer'
|
14
|
-
require File.dirname(__FILE__) + '/../console/web_console'
|
15
|
-
|
16
|
-
module Logman
|
17
|
-
class Config
|
3
|
+
class Logman
|
4
|
+
class Config < Hash
|
5
|
+
|
18
6
|
attr_accessor :log_writer
|
19
|
-
attr_accessor :web_console
|
20
7
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def database_name=(val)
|
26
|
-
MongoMapper.database = val
|
27
|
-
end
|
8
|
+
#logman as webconsole and api
|
9
|
+
attr_accessor :web_console
|
10
|
+
attr_accessor :database_config
|
28
11
|
|
29
|
-
|
30
|
-
|
31
|
-
|
12
|
+
# logman as proxy
|
13
|
+
attr_accessor :logman_endpoin
|
14
|
+
attr_accessor :write_token
|
15
|
+
attr_accessor :public_endpoint
|
32
16
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
17
|
+
def initialize
|
18
|
+
@log_writer = Logman::LogWriter
|
19
|
+
@web_console = Logman::WebConsole
|
20
|
+
|
21
|
+
@database_config = './database.yaml'
|
36
22
|
end
|
37
23
|
|
38
|
-
|
39
|
-
|
40
|
-
|
24
|
+
|
41
25
|
@@instance = nil
|
42
26
|
def self.instance
|
43
27
|
@@instance = Config.new if @@instance.nil?
|
@@ -45,8 +29,15 @@ module Logman
|
|
45
29
|
end
|
46
30
|
end
|
47
31
|
|
32
|
+
def self.env
|
33
|
+
en = ENV['RACK_ENV'] || 'production'
|
34
|
+
en.to_sym
|
35
|
+
end
|
36
|
+
|
48
37
|
def self.configure(&block)
|
49
|
-
block.call Logman::Config.instance
|
38
|
+
block.call Logman::Config.instance if block
|
39
|
+
|
40
|
+
Mongoid.load!(Logman::Config.instance.database_config, Logman.env)
|
50
41
|
|
51
42
|
require File.dirname(__FILE__) + '/../logman/server'
|
52
43
|
end
|
data/lib/logman/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
class Logman
|
2
|
+
VERSION = "0.1.0.alpha"
|
3
3
|
end
|
data/lib/models/bucket.rb
CHANGED
@@ -1,38 +1,57 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
class Logman
|
3
3
|
class Bucket
|
4
|
-
include
|
5
|
-
|
4
|
+
include Mongoid::Document
|
5
|
+
store_in collection: 'logman_buckets'
|
6
6
|
|
7
|
-
|
7
|
+
attr_protected :write_token
|
8
|
+
validates_presence_of :name
|
9
|
+
validates_format_of :name, with: /[A-Za-z0-9_]+/
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
field :name, type: String
|
12
|
+
field :write_token,type: String
|
13
|
+
field :user_ids, type: Array
|
12
14
|
|
13
|
-
|
15
|
+
#collection specifications
|
16
|
+
def self.set_bucket_collection(name)
|
17
|
+
Thread.current[:bucket_key] = name
|
18
|
+
end
|
14
19
|
|
15
|
-
|
20
|
+
def logs
|
21
|
+
Bucket.set_bucket_collection(self.bucket_key)
|
22
|
+
Log.all
|
23
|
+
end
|
24
|
+
#end
|
16
25
|
|
17
26
|
def user_ids=(val)
|
18
|
-
val = val.map {|key| BSON::ObjectId(key) }
|
27
|
+
val = val.map {|key| Moped::BSON::ObjectId.from_string(key) }
|
19
28
|
write_attribute(:user_ids, val)
|
20
29
|
end
|
21
30
|
|
22
|
-
|
31
|
+
def users
|
32
|
+
User.where(:id.in => :user_ids)
|
33
|
+
end
|
34
|
+
|
35
|
+
def bucket_key
|
36
|
+
key = self.name.gsub(' ','_').gsub('-','_')
|
37
|
+
"bucket_#{key.underscore}"
|
38
|
+
end
|
23
39
|
|
40
|
+
before_create :new_token
|
24
41
|
def new_token
|
25
42
|
self.write_token = generate_new_token
|
26
43
|
end
|
27
44
|
|
28
|
-
|
29
45
|
def generate_new_token
|
30
46
|
while true
|
31
47
|
token = SecureRandom.hex
|
32
|
-
return token if Bucket.
|
48
|
+
return token if Bucket.where(:write_token=> token).count == 0
|
33
49
|
end
|
34
50
|
end
|
35
51
|
|
36
|
-
|
52
|
+
def serializable_hash(options={})
|
53
|
+
options[:methods] ||= [:id]
|
54
|
+
super(options)
|
55
|
+
end
|
37
56
|
end
|
38
57
|
end
|
data/lib/models/log.rb
CHANGED
@@ -1,41 +1,55 @@
|
|
1
|
-
|
1
|
+
class Logman
|
2
2
|
class Log
|
3
|
-
include
|
4
|
-
|
5
|
-
attr_accessible :log_type, :data_type, :message, :data, :datetime,:sources
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps::Created
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
store_in collection: lambda { Thread.current[:bucket_key] }
|
7
|
+
|
8
|
+
validates_presence_of :log_type, :message
|
9
|
+
|
10
|
+
field :log_type, type: Integer #1-error, 2-success, 3-warning, 4-info
|
11
|
+
field :data_type, type: String #application that generated log like syslog,
|
12
|
+
field :message, type: String #short string message
|
13
|
+
field :data, type: Hash
|
14
|
+
field :datetime, type: Time
|
15
|
+
|
16
|
+
embeds_many :sources, :class_name=>'Logman::Source'
|
9
17
|
|
10
|
-
key :message, String, :required=>true #short string message
|
11
|
-
key :data, Hash
|
12
18
|
|
13
|
-
key :datetime, Time
|
14
19
|
|
15
|
-
many :sources, :class_name=>'Logman::Source'
|
16
20
|
|
17
21
|
def self.count_on_date(date)
|
18
|
-
begin
|
22
|
+
# begin
|
19
23
|
# raise date.to_s
|
20
24
|
start_time = Time.new(date.year, date.month, date.day, 0,0,0).utc
|
21
|
-
end_time =
|
25
|
+
end_time = start_time + 1.day
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
count = 0
|
28
|
+
|
29
|
+
Bucket.all.each do |b|
|
30
|
+
count += b.logs.between(created_at: start_time..end_time).count
|
31
|
+
end
|
32
|
+
count
|
33
|
+
#
|
34
|
+
# rescue
|
35
|
+
# 0
|
36
|
+
# end
|
27
37
|
end
|
28
38
|
|
29
|
-
|
39
|
+
#to json
|
40
|
+
def serializable_hash(options={})
|
41
|
+
options[:methods] ||= [:id]
|
42
|
+
super(options)
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
|
33
47
|
class Source
|
34
|
-
include
|
35
|
-
|
48
|
+
include Mongoid::Document
|
49
|
+
embedded_in :log, :class_name=>'Logman::Log'
|
36
50
|
|
37
|
-
|
38
|
-
|
39
|
-
|
51
|
+
field :name, type: String
|
52
|
+
field :ip_address, type: String
|
53
|
+
field :hop, type: Integer
|
40
54
|
end
|
41
55
|
end
|
data/lib/models/user.rb
CHANGED
@@ -1,29 +1,36 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
|
3
|
+
class Logman
|
4
4
|
class User
|
5
|
-
include
|
5
|
+
include Mongoid::Document
|
6
|
+
include ActiveModel::SecurePassword
|
6
7
|
|
8
|
+
store_in collection: 'logman_users'
|
7
9
|
|
8
|
-
|
10
|
+
attr_accessible :email, :password, :name, :admin
|
9
11
|
|
10
|
-
|
12
|
+
validates_presence_of :email, :name
|
13
|
+
validates_presence_of :password, :on=> :create
|
14
|
+
validates_uniqueness_of :email
|
15
|
+
validates_format_of :email, with: /.+\@.+\..+/
|
11
16
|
|
12
|
-
|
17
|
+
field :email, type: String
|
18
|
+
field :password_digest, type: String
|
19
|
+
field :name, type: String
|
20
|
+
field :admin, type: Boolean
|
13
21
|
|
14
|
-
|
15
|
-
key :password_digest, String #, :required=>true
|
16
|
-
key :name, String, :required=>true
|
17
|
-
key :admin, Boolean
|
22
|
+
has_secure_password
|
18
23
|
|
19
24
|
# buckets that user have access
|
20
25
|
def buckets
|
21
|
-
return Bucket.
|
26
|
+
return Bucket.all if self.admin
|
22
27
|
|
23
28
|
Bucket.where(:user_ids=> self.id)
|
24
29
|
end
|
25
30
|
|
31
|
+
|
26
32
|
def serializable_hash(options={})
|
33
|
+
options[:methods] ||= [:id]
|
27
34
|
options[:except] ||= [:password_digest]
|
28
35
|
super(options)
|
29
36
|
end
|
data/lib/modules/log_writer.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
-
|
1
|
+
class Logman
|
2
2
|
|
3
3
|
class LogWriter < Sinatra::Base
|
4
4
|
post '/api/write' do
|
5
5
|
json = JSON.parse(request.body.read)
|
6
|
-
bucket = Bucket.
|
6
|
+
bucket = Bucket.where(:write_token=>params[:key]).first
|
7
|
+
|
7
8
|
if bucket.nil?
|
8
9
|
status 401
|
9
10
|
return 'Invalid token'
|
10
11
|
end
|
11
12
|
|
13
|
+
Bucket.set_bucket_collection bucket.bucket_key
|
14
|
+
|
12
15
|
log = Log.new(json)
|
13
16
|
log.datetime = Time.now if log.datetime.blank?
|
14
|
-
log.bucket = bucket
|
15
|
-
|
16
17
|
|
17
18
|
if log.save
|
18
19
|
return status 200
|
data/logman.gemspec
CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
-
|
24
|
-
spec.add_development_dependency "sinatra"
|
25
|
-
spec.add_development_dependency "sinatra-contrib"
|
26
23
|
spec.add_development_dependency "bson_ext"
|
27
|
-
|
28
|
-
spec.
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "sinatra", "~> 1.4.4"
|
26
|
+
spec.add_runtime_dependency "sinatra-contrib", "~> 1.4.2"
|
27
|
+
spec.add_runtime_dependency "mongoid", "~> 3.1.6"
|
28
|
+
spec.add_runtime_dependency "bcrypt-ruby", '~> 3.0.0'
|
29
29
|
|
30
30
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0.alpha
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Branko Krstic
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: bson_ext
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
@@ -60,53 +60,53 @@ dependencies:
|
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name: sinatra
|
63
|
+
name: sinatra
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
type: :
|
69
|
+
version: 1.4.4
|
70
|
+
type: :runtime
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
75
|
+
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: 1.4.4
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: sinatra-contrib
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
86
|
-
type: :
|
85
|
+
version: 1.4.2
|
86
|
+
type: :runtime
|
87
87
|
prerelease: false
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
89
|
none: false
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
93
|
+
version: 1.4.2
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: mongoid
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
|
-
- -
|
99
|
+
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
102
|
-
type: :
|
101
|
+
version: 3.1.6
|
102
|
+
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
|
-
- -
|
107
|
+
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 3.1.6
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: bcrypt-ruby
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,15 +114,15 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - ~>
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 3.
|
118
|
-
type: :
|
117
|
+
version: 3.0.0
|
118
|
+
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
none: false
|
122
122
|
requirements:
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: 3.
|
125
|
+
version: 3.0.0
|
126
126
|
description: Logman is Web Console/API for gathering logs from various sources and
|
127
127
|
analyzing them. Logs are saved to mongo database.
|
128
128
|
email:
|
@@ -137,9 +137,11 @@ files:
|
|
137
137
|
- README.md
|
138
138
|
- Rakefile
|
139
139
|
- config.ru
|
140
|
+
- database.yaml
|
140
141
|
- lib/console/auth.rb
|
141
142
|
- lib/console/base.rb
|
142
143
|
- lib/console/bucket_api.rb
|
144
|
+
- lib/console/lib/query_builder.rb
|
143
145
|
- lib/console/log_api.rb
|
144
146
|
- lib/console/static/app/api_guide/index.html
|
145
147
|
- lib/console/static/app/bucket/add_edit.html
|
@@ -231,7 +233,6 @@ files:
|
|
231
233
|
- lib/models/log.rb
|
232
234
|
- lib/models/user.rb
|
233
235
|
- lib/modules/log_writer.rb
|
234
|
-
- lib/modules/secure_password.rb
|
235
236
|
- logman.gemspec
|
236
237
|
homepage: ''
|
237
238
|
licenses:
|
@@ -249,9 +250,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
249
250
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
251
|
none: false
|
251
252
|
requirements:
|
252
|
-
- - ! '
|
253
|
+
- - ! '>'
|
253
254
|
- !ruby/object:Gem::Version
|
254
|
-
version:
|
255
|
+
version: 1.3.1
|
255
256
|
requirements: []
|
256
257
|
rubyforge_project:
|
257
258
|
rubygems_version: 1.8.23
|
@@ -1,122 +0,0 @@
|
|
1
|
-
module MongoMapper
|
2
|
-
module SecurePassword
|
3
|
-
class << self; attr_accessor :min_cost; end
|
4
|
-
self.min_cost = false
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
# Adds methods to set and authenticate against a BCrypt password.
|
8
|
-
# This mechanism requires you to have a password_digest attribute.
|
9
|
-
#
|
10
|
-
# Validations for presence of password on create, confirmation of password
|
11
|
-
# (using a +password_confirmation+ attribute) are automatically added. If
|
12
|
-
# you wish to turn off validations, pass <tt>validations: false</tt> as an
|
13
|
-
# argument. You can add more validations by hand if need be.
|
14
|
-
#
|
15
|
-
# If you don't need the confirmation validation, just don't set any
|
16
|
-
# value to the password_confirmation attribute and the the validation
|
17
|
-
# will not be triggered.
|
18
|
-
#
|
19
|
-
# You need to add bcrypt-ruby (~> 3.1.2) to Gemfile to use #has_secure_password:
|
20
|
-
#
|
21
|
-
# gem 'bcrypt-ruby', '~> 3.1.2'
|
22
|
-
#
|
23
|
-
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
|
24
|
-
#
|
25
|
-
# # Schema: User(name:string, password_digest:string)
|
26
|
-
# class User < ActiveRecord::Base
|
27
|
-
# has_secure_password
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
|
31
|
-
# user.save # => false, password required
|
32
|
-
# user.password = 'mUc3m00RsqyRe'
|
33
|
-
# user.save # => false, confirmation doesn't match
|
34
|
-
# user.password_confirmation = 'mUc3m00RsqyRe'
|
35
|
-
# user.save # => true
|
36
|
-
# user.authenticate('notright') # => false
|
37
|
-
# user.authenticate('mUc3m00RsqyRe') # => user
|
38
|
-
# User.find_by(name: 'david').try(:authenticate, 'notright') # => false
|
39
|
-
# User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
|
40
|
-
def has_secure_password(options = {})
|
41
|
-
# Load bcrypt-ruby only when has_secure_password is used.
|
42
|
-
# This is to avoid ActiveModel (and by extension the entire framework)
|
43
|
-
# being dependent on a binary library.
|
44
|
-
begin
|
45
|
-
gem 'bcrypt-ruby', '~> 3.1.2'
|
46
|
-
require 'bcrypt'
|
47
|
-
rescue LoadError
|
48
|
-
$stderr.puts "You don't have bcrypt-ruby installed in your application. Please add it to your Gemfile and run bundle install"
|
49
|
-
raise
|
50
|
-
end
|
51
|
-
|
52
|
-
attr_reader :password
|
53
|
-
|
54
|
-
include InstanceMethodsOnActivation
|
55
|
-
|
56
|
-
if options.fetch(:validations, true)
|
57
|
-
validates_confirmation_of :password, if: lambda { |m| m.password.present? }
|
58
|
-
validates_presence_of :password, :on => :create
|
59
|
-
validates_presence_of :password_confirmation, if: lambda { |m| m.password.present? }
|
60
|
-
|
61
|
-
before_create { raise "Password digest missing on new record" if password_digest.blank? }
|
62
|
-
end
|
63
|
-
|
64
|
-
if respond_to?(:attributes_protected_by_default)
|
65
|
-
def self.attributes_protected_by_default #:nodoc:
|
66
|
-
super + ['password_digest']
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
module InstanceMethodsOnActivation
|
73
|
-
# Returns +self+ if the password is correct, otherwise +false+.
|
74
|
-
#
|
75
|
-
# class User < ActiveRecord::Base
|
76
|
-
# has_secure_password validations: false
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
|
80
|
-
# user.save
|
81
|
-
# user.authenticate('notright') # => false
|
82
|
-
# user.authenticate('mUc3m00RsqyRe') # => user
|
83
|
-
def authenticate(unencrypted_password)
|
84
|
-
BCrypt::Password.new(password_digest) == unencrypted_password && self
|
85
|
-
end
|
86
|
-
|
87
|
-
# Encrypts the password into the +password_digest+ attribute, only if the
|
88
|
-
# new password is not blank.
|
89
|
-
#
|
90
|
-
# class User < ActiveRecord::Base
|
91
|
-
# has_secure_password validations: false
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# user = User.new
|
95
|
-
# user.password = nil
|
96
|
-
# user.password_digest # => nil
|
97
|
-
# user.password = 'mUc3m00RsqyRe'
|
98
|
-
# user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."
|
99
|
-
def password=(unencrypted_password)
|
100
|
-
unless unencrypted_password.blank?
|
101
|
-
@password = unencrypted_password
|
102
|
-
cost = MongoMapper::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
|
103
|
-
self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def password_confirmation=(unencrypted_password)
|
108
|
-
@password_confirmation = unencrypted_password
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
module Document
|
114
|
-
extend MongoMapper::SecurePassword::ClassMethods
|
115
|
-
|
116
|
-
def self.included(base)
|
117
|
-
base.send :extend, MongoMapper::SecurePassword::ClassMethods
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
|