logman 0.0.2 → 0.1.0.alpha
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.
- 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
|
+

|
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
|
-
|