marty 1.0.43 → 1.0.44

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b66276891458efd498648be59d402697d007be05
4
- data.tar.gz: 6fd5ee9414488b17042c87bb1439ca1021d371b6
3
+ metadata.gz: 817a8f32d8a912597e8941cb60889a6f9e3723bc
4
+ data.tar.gz: cccaf421c0216156db7c106b69577f0e363c4c58
5
5
  SHA512:
6
- metadata.gz: acff2e6a1842b34ed8ec5c17e8d15bd314723eae74cc11e043ca8f4f23bee95da6c0a46a56dca72bec7e248878f2849b517fb8f8397f3f1873ffd3658bd6c0d5
7
- data.tar.gz: b596a59fd785a72531318a652dc9f20c71944df9a433e5b8db183316d4434015c974cc0276940ca7c3d418f94e49fbd07d6fbc228447c2fd63172f03bab0ff4c
6
+ metadata.gz: 030c85527c4809aeb5a18634425c5dc5924534b7f8b3f44fc83189adccfc7724b87b97e06cdeac5c5004b1301c4f9745918bcb47c8004ac0b07492d6e2fcc2b3
7
+ data.tar.gz: dcbabb68d76e981e927eda2e9c8e9b3a31a4896ef66561f7bcaa1d553fc31f4b8e5d056b084b7199982e242f67938964ec59366b645588c7e266a97d9ea724aa
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- marty (1.0.43)
4
+ marty (1.0.44)
5
5
  axlsx (= 2.1.0pre)
6
6
  coderay
7
7
  delorean_lang (~> 0.1)
@@ -11,7 +11,7 @@ class Marty::LogView < Marty::Grid
11
11
  c.paging = :buffered
12
12
  c.editing = :in_form
13
13
  c.attributes = [
14
- :timestamp,
14
+ :timestamp_custom,
15
15
  :message_type,
16
16
  :message,
17
17
  :details
@@ -26,7 +26,7 @@ class Marty::LogView < Marty::Grid
26
26
 
27
27
  def default_form_items
28
28
  [
29
- :timestamp,
29
+ :timestamp_custom,
30
30
  :message_type,
31
31
  :message,
32
32
  textarea_field(:details).merge!({height: 400})
@@ -50,26 +50,38 @@ class Marty::LogView < Marty::Grid
50
50
  c.read_only = true
51
51
  end
52
52
 
53
- attribute :timestamp do |c|
53
+ # FIXME?: timestamp_custom is needed to display datetime data proprely
54
+ # UI does not interact well with AR/PG and doesn't display fractional s
55
+ # This work around requires explicit sorting/filtering
56
+ attribute :timestamp_custom do |c|
54
57
  c.text = I18n.t("log_grid.timestamp")
55
58
  c.width = 200
56
59
  c.read_only = true
60
+ c.filterable = true
57
61
  c.xtype = :datecolumn
58
62
  c.format = 'Y-m-d h:i:s.u'
59
63
  c.field_config = {
60
64
  xtype: :displayfield,
61
65
  }
62
66
  c.getter = lambda { |r| Time.at(r.timestamp) }
67
+ c.sorting_scope = lambda {|r, dir| r.order("timestamp " + dir.to_s)}
68
+
69
+ # FIXME?: The UI AR/PG DateTime workaround requires the timestamp to be cast
70
+ # to text in order to compare filter input using the LIKE operator.
71
+ # Otherwise it will fail. '<' and '>' functionality is missing.
72
+ c.filter_with = lambda {|r, v, op|
73
+ r.where("timestamp::text #{op} '#{v}%'")}
63
74
  end
64
75
 
65
76
  column :details do |c|
66
- c.getter = lambda { |r| CGI.escapeHTML(r.details) }
77
+ c.getter = lambda { |r| CGI.escapeHTML(r.details.pretty_inspect) }
67
78
  end
68
79
 
69
80
  attribute :details do |c|
70
81
  c.text = I18n.t("log_grid.details")
71
82
  c.width = 900
72
83
  c.read_only = true
84
+ c.getter = lambda { |r| r.details.to_s}
73
85
  end
74
86
  end
75
87
 
@@ -1,69 +1,22 @@
1
1
  class Marty::Log < Marty::Base
2
-
3
- def self.logfile
4
- @logfile ||= Rails.root.join('log', Rails.env + '.sql').to_s
5
- end
6
-
7
- establish_connection({
8
- adapter: "sqlite3",
9
- database: logfile
10
- })
11
- self.table_name = "log"
12
- self.primary_key = "id"
13
-
14
- def self.db_init
15
- db = SQLite3::Database.new(Marty::Log.logfile)
16
- db.execute <<-SQL
17
- CREATE TABLE IF NOT EXISTS log (
18
- id INTEGER PRIMARY KEY,
19
- message_type TEXT,
20
- message TEXT,
21
- timestamp REAL,
22
- details BLOB )
23
- SQL
24
- db
25
- end
2
+ # establish_connection creates a connection using the connection pool
3
+ # based on the current AR connection (i.e. duplicates AR connection)
4
+ establish_connection
26
5
 
27
6
  def self.write_log(type, message, details)
28
7
  begin
29
- @db ||= db_init
30
- stmt = @db.prepare <<-SQL
31
- INSERT INTO log (message_type, message, timestamp, details)
32
- values (?, ?, ?, ?)
33
- SQL
34
- stmt.bind_param(1, type.to_s)
35
- stmt.bind_param(2, message)
36
- stmt.bind_param(3, Time.zone.now.to_f)
37
- stmt.bind_param(4, details.pretty_inspect)
38
-
39
- sent = false
40
- retries = 3
41
- delay = 0.1
42
- until sent
43
- begin
44
- stmt.execute
45
- sent = true
46
- rescue SQLite3::BusyException
47
- raise if retries == 0
48
- retries -= 1
49
- sleep delay
50
- end
51
- end
52
-
8
+ create!(message_type: type,
9
+ message: message,
10
+ details: details,
11
+ timestamp: Time.zone.now)
53
12
  rescue => e
54
13
  Marty::Util.logger.error("Marty::Logger failure: #{e.message}")
55
- ensure
56
- stmt.close if stmt rescue nil
57
14
  end
58
15
  end
59
16
 
60
17
  def self.cleanup(days_to_keep)
61
18
  raise "Must give numeric value. (Got '#{days_to_keep}')" unless
62
19
  (Float(days_to_keep) rescue false)
63
- @db ||= db_init
64
- cutoff = Time.zone.now.to_i - days_to_keep.to_i*60*60*24
65
- @db.execute <<-SQL
66
- delete from log where timestamp <= #{cutoff}
67
- SQL
20
+ where("timestamp <= ?", Time.zone.now - days_to_keep.to_i.days).delete_all
68
21
  end
69
22
  end
@@ -0,0 +1,10 @@
1
+ class CreateMartyLogs < ActiveRecord::Migration
2
+ def change
3
+ create_table :marty_logs do |t|
4
+ t.string :message_type, null: false
5
+ t.string :message, null: false
6
+ t.jsonb :details, null: true
7
+ t.datetime :timestamp, null: false
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,3 @@
1
- require 'sqlite3'
2
-
3
1
  class Marty::Logger
4
2
 
5
3
  def self.method_missing(m, *args, &block)
@@ -17,10 +15,9 @@ class Marty::Logger
17
15
  begin
18
16
  yield
19
17
  rescue => e
20
- error(error_message, { message: e.message,
21
- data: error_data })
18
+ error(error_message, { "message" => e.message,
19
+ "data" => error_data})
22
20
  raise "#{error_message}: #{e.message}"
23
21
  end
24
22
  end
25
-
26
23
  end
@@ -1,3 +1,3 @@
1
1
  module Marty
2
- VERSION = "1.0.43"
2
+ VERSION = "1.0.44"
3
3
  end
@@ -353,6 +353,10 @@ describe Marty::RpcController do
353
353
  @data_json = [@data].to_json
354
354
  }
355
355
 
356
+ after(:each) do
357
+ Marty::Log.delete_all
358
+ end
359
+
356
360
  let(:t1) { @t1 }
357
361
  let(:t2) { @t2 }
358
362
  let(:p0) { @p0 }
@@ -716,15 +720,6 @@ describe Marty::RpcController do
716
720
  end
717
721
 
718
722
  context "output_validation" do
719
- before(:all) do
720
- @db = SQLite3::Database.new(Marty::Log.logfile)
721
- end
722
- before(:each) do
723
- @logid = @db.execute('select max(id) from log').first.first || 0 rescue 0
724
- end
725
- after(:all) do
726
- @db.close
727
- end
728
723
  it "validates output" do
729
724
  Marty::ApiConfig.create!(script: "M4",
730
725
  node: "A",
@@ -744,7 +739,7 @@ describe Marty::RpcController do
744
739
  res_hash = JSON.parse(response.body)
745
740
  expect(res_hash).to eq([135,291,[{"a"=>132,"b"=>456},
746
741
  {"a"=>789,"b"=>132}]])
747
- logs = Marty::Log.where("id > #{@logid}").to_a
742
+ logs = Marty::Log.all
748
743
  expect(logs.count).to eq(0)
749
744
  end
750
745
 
@@ -781,20 +776,19 @@ describe Marty::RpcController do
781
776
  expect(res_hash[0]["error"]).to include(expect1)
782
777
  expect(res_hash[0]["error"]).to include(expect2)
783
778
 
784
- logs = Marty::Log.where("id > #{@logid}").to_a
779
+ logs = Marty::Log.all
785
780
  expect(logs.count).to eq(2)
786
781
  expect(logs[0].message).to eq("API M5:A.result")
787
782
  expect(logs[1].message).to eq("API M5:A.result2")
788
783
  logs.each do |ml|
789
- expect(ml.details).to include(expect1)
790
- expect(ml.details).to include(expect2)
791
- expect(ml.details).to include(
792
- ":data=>[{\"a\"=>\"str\", \"b\"=>456}, {\"a\"=>789, \"b\"=>\"str\"}]}")
784
+ expect(ml.details["error"].join).to include(expect1)
785
+ expect(ml.details["error"].join).to include(expect2)
786
+ expect(ml.details["data"]).to eq([{"a"=>"str", "b"=>456},
787
+ {"a"=>789, "b"=>"str"}])
793
788
  end
794
789
  end
795
790
 
796
791
  it "validates output (missing item)" do
797
- logid = @db.execute('select max(id) from log').first.first rescue 0
798
792
  Marty::ApiConfig.create!(script: "M9",
799
793
  node: "A",
800
794
  attr: nil,
@@ -818,13 +812,13 @@ describe Marty::RpcController do
818
812
  expect(res_hash[0]["error"]).to include(expect1)
819
813
  expect(res_hash[0]["error"]).to include(expect2)
820
814
 
821
- logs = Marty::Log.where("id > #{@logid}").to_a
815
+ logs = Marty::Log.all
822
816
  expect(logs.count).to eq(1)
823
817
  expect(logs[0].message).to eq("API M9:A.result")
824
- expect(logs[0].details).to include(expect1)
825
- expect(logs[0].details).to include(expect2)
826
- expect(logs[0].details).to include(
827
- ":data=>[{\"a\"=>1, \"b\"=>123}, {\"a\"=>789, \"b\"=>123}]")
818
+ expect(logs[0].details["error"].join).to include(expect1)
819
+ expect(logs[0].details["error"].join).to include(expect2)
820
+ expect(logs[0].details["data"]).to eq([{"a"=>1, "b"=>123},
821
+ {"a"=>789, "b"=>123}])
828
822
  end
829
823
  end
830
824
 
@@ -2,23 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  feature 'logger view', js: true, capybara: true do
4
4
 
5
- def manual_insert(type, message, ts, detail)
6
- stmt = @db.prepare <<-SQL
7
- INSERT INTO log (message_type, message, timestamp, details)
8
- VALUES (?, ?, ?, ?)
9
- SQL
10
- stmt.bind_param(1, type)
11
- stmt.bind_param(2, message)
12
- stmt.bind_param(3, ts)
13
- stmt.bind_param(4, detail)
14
- stmt.execute
15
- stmt.close
16
- end
17
-
18
5
  before(:all) do
19
6
  self.use_transactional_fixtures = false
20
- @db = SQLite3::Database.new(Marty::Log.logfile)
21
- @db.execute("delete from log")
7
+ Marty::Log.delete_all
22
8
 
23
9
  info_s = { info: 'message' }
24
10
  error_s = [1, 2, 3, { error: 'message' }]
@@ -26,13 +12,20 @@ feature 'logger view', js: true, capybara: true do
26
12
  Marty::Logger.info('info message', nil)
27
13
  Marty::Logger.error('error message', error_s)
28
14
  Marty::Logger.fatal('fatal message', fatal_s)
29
- manual_insert("debug", "hi mom", (Time.zone.now - 5.days).to_i,
30
- ["one", "two", 3, 4.0].pretty_inspect)
31
- manual_insert("warn", "all your base", (Time.zone.now - 10.days).to_i,
32
- [5].pretty_inspect)
33
- @ts = (@db.execute "select timestamp from log order by timestamp desc").map do
15
+
16
+ Marty::Log.create!(message_type: "debug",
17
+ message: "hi mom",
18
+ details: ["one", "two", 3, 4.0],
19
+ timestamp: Time.zone.now - 5.days)
20
+
21
+ Marty::Log.create!(message_type: "warn",
22
+ message: "all your base",
23
+ details: [5],
24
+ timestamp: Time.zone.now - 10.days)
25
+
26
+ @ts = Marty::Log.select(:timestamp).order(timestamp: :desc).map do
34
27
  |(ts)|
35
- Time.zone.at(ts).strftime('%Y-%m-%dT%H:%M:%S.%L%:z')
28
+ Time.zone.at(ts[:timestamp]).strftime('%Y-%m-%dT%H:%M:%S.%L%:z')
36
29
  end
37
30
 
38
31
  @clean_file = "/tmp/clean_#{Process.pid}.psql"
@@ -42,8 +35,7 @@ feature 'logger view', js: true, capybara: true do
42
35
 
43
36
  after(:all) do
44
37
  restore_clean_db(@clean_file)
45
- @db.execute "delete from log"
46
- @db.close
38
+ Marty::Log.delete_all
47
39
  self.use_transactional_fixtures = true
48
40
  end
49
41
 
@@ -54,16 +46,18 @@ feature 'logger view', js: true, capybara: true do
54
46
  show_submenu('Log Maintenance')
55
47
  press('View Log')
56
48
  wait_for_ready
49
+
57
50
  exp_types = ["fatal", "error", "info", "debug", "warn"]
58
51
  exp_messages = ["fatal message", "error message",
59
52
  "info message", "hi mom", "all your base"]
60
- exp_details = [ "[\"string\", 123, {:fatal=>\"message\", "\
61
- ":another_key=>\"value\"}]\n",
62
- "[1, 2, 3, {:error=>\"message\"}]\n",
53
+ exp_details = [ "[\"string\", 123, {\"fatal\"=>\"message\", "\
54
+ "\"another_key\"=>\"value\"}]\n",
55
+ "[1, 2, 3, {\"error\"=>\"message\"}]\n",
63
56
  "nil\n",
64
57
  "[\"one\", \"two\", 3, 4.0]\n",
65
- "[5]\n"]
66
- [[nil, 5], [7, 4], [3, 3], [0, 0]].each do |days, exp_count|
58
+ "[5]\n"
59
+ ]
60
+ [[nil, 5], [7, 4], [3, 3], [0, 0]].each do |days, exp_count|
67
61
  if days
68
62
  press('System')
69
63
  show_submenu('Log Maintenance')
@@ -75,13 +69,14 @@ feature 'logger view', js: true, capybara: true do
75
69
  find(:refresh).click
76
70
  wait_for_ready
77
71
  end
72
+
78
73
  cnt = logview.row_count()
79
74
  expect(cnt).to eq(exp_count)
80
75
  types = logview.col_values('message_type', cnt, 0)
81
76
  messages = logview.col_values('message', cnt, 0)
82
77
  details = logview.col_values('details', cnt, 0).
83
- map { |d| CGI.unescapeHTML(d) }
84
- ts = logview.col_values('timestamp', cnt, 0)
78
+ map { |d| CGI.unescapeHTML(d) }
79
+ ts = logview.col_values('timestamp_custom', cnt, 0)
85
80
  expect(ts).to eq(@ts.slice(0,exp_count))
86
81
  expect(types).to eq(exp_types.slice(0,exp_count))
87
82
  expect(messages).to eq(exp_messages.slice(0,exp_count))
@@ -7,48 +7,36 @@ module Marty
7
7
  self.use_transactional_fixtures = false
8
8
  end
9
9
  before(:each) do
10
- @db = SQLite3::Database.new(Marty::Log.logfile)
11
- @db.execute "delete from log"
12
- end
13
- after(:each) do
14
- @db.close
10
+ Marty::Log.delete_all
15
11
  end
16
12
  after(:all) do
17
13
  self.use_transactional_fixtures = true
18
14
  end
19
15
 
16
+ it "log has its own connection" do
17
+ expect(Marty::Log.connection).not_to equal(Marty::Posting.connection)
18
+ expect(Marty::Posting.connection).to equal(Marty::Script.connection)
19
+ end
20
+
20
21
  it "logs" do
21
- File.open(Rails.root.join("log/test.log")) do |f|
22
- f.seek(0, IO::SEEK_END)
23
- info_s = { info: 'message' }
24
- error_s = [1, 2, 3, { error: 'message' }]
25
- fatal_s = ["string", 123, { fatal: "message", another_key: 'value' }]
26
- Marty::Logger.info('info message', info_s)
27
- Marty::Logger.error('error message', error_s)
28
- Marty::Logger.fatal('fatal message', fatal_s)
29
- rails_log = f.readlines
30
- log = @db.execute "select * from log"
31
- log_detail = []
32
- log_ts = []
33
- log.each do |l|
34
- id, type, msg, ts, detail_str = l
35
- log_detail[id] = [type, msg, detail_str]
36
- log_ts[id] = ts
37
- end
38
- expect(rails_log).to eq(["info message\n",
39
- "error message\n",
40
- "fatal message\n"])
41
- expect(log_detail[1]).to eq(["info", "info message",
42
- info_s.pretty_inspect])
43
- expect(log_detail[2]).to eq(["error", "error message",
44
- error_s.pretty_inspect])
45
- expect(log_detail[3]).to eq(["fatal", "fatal message",
46
- fatal_s.pretty_inspect])
47
- (1..3).each do |idx|
48
- expect(log_ts[idx]).to be_within(5).of(Time.zone.now.to_i)
49
- end
22
+ info_s = {'info' => 'message'}
23
+ error_s = [1, 2, 3, {'error' =>'message'}]
24
+ fatal_s = ["string", 123, {'fatal' => "message",
25
+ 'another_key' => 'value'}]
26
+ Marty::Logger.info('info message', info_s)
27
+ Marty::Logger.error('error message', error_s)
28
+ Marty::Logger.fatal('fatal message', fatal_s)
29
+ log = Marty::Log.all
30
+ log_detail = log.map{|l| [l[:message_type], l[:message], l[:details]]}
31
+ log_ts = log.map{|l| l[:timestamp]}
32
+ expect(log_detail[0]).to eq(["info", "info message", info_s])
33
+ expect(log_detail[1]).to eq(["error", "error message", error_s])
34
+ expect(log_detail[2]).to eq(["fatal", "fatal message", fatal_s])
35
+ log_ts.each do |ts|
36
+ expect(ts.to_i).to be_within(5).of(Time.zone.now.to_i)
50
37
  end
51
38
  end
39
+
52
40
  it "with_logging" do
53
41
  bd = 'block description'
54
42
  the_error = 'error during my block'
@@ -64,40 +52,11 @@ module Marty
64
52
  log = Marty::Log.first
65
53
  expect(log.message_type).to eq('error')
66
54
  expect(log.message).to eq(bd)
67
- expect(log.details).to eq({ message: the_error,
68
- data: data }.pretty_inspect)
69
- end
70
- end
71
- describe "Logger errors" do
72
- it "fails gracefully" do
73
- allow(Marty::Log).to receive(:db_init).
74
- and_raise("Error initializing DB")
75
- Marty::Log.instance_variable_set(:@db, nil)
76
- File.open(Rails.root.join("log/test.log")) do |f|
77
- f.seek(0, IO::SEEK_END)
78
- expect{Marty::Logger.info('info message', [1,2,3])}.not_to raise_error
79
- rails_log = f.readlines
80
- expect(rails_log).to eq(["info message\n",
81
- "Marty::Logger failure: Error initializing DB\n"])
82
- end
83
- end
84
- it "fails gracefully in ensure" do
85
- Marty::Logger.info('init db', [])
86
- close_err = 'Error closing statement'
87
- allow_any_instance_of(SQLite3::Statement).to receive(:close).
88
- and_raise(close_err)
89
- File.open(Rails.root.join("log/test.log")) do |f|
90
- f.seek(0, IO::SEEK_END)
91
- expect{Marty::Logger.info('ensure message', [1,2,3])}.not_to raise_error
92
- rails_log = f.readlines
93
- expect(rails_log).to eq(["ensure message\n"])
94
- allow_any_instance_of(SQLite3::Statement).to receive(:close).
95
- and_call_original
96
- sleep 1
97
- Marty::Log.cleanup(0)
98
- end
55
+ expect(log.details).to eq({ "message" => the_error,
56
+ "data" => JSON.parse(data.to_json)})
99
57
  end
100
58
  end
59
+
101
60
  describe "Exercise" do
102
61
  before(:all) do
103
62
  @clean_file = "/tmp/clean_#{Process.pid}.psql"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marty
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.43
4
+ version: 1.0.44
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arman Bostani
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2017-10-09 00:00:00.000000000 Z
17
+ date: 2017-10-11 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: pg
@@ -477,6 +477,7 @@ files:
477
477
  - db/migrate/300_create_marty_api_configs.rb
478
478
  - db/migrate/301_create_marty_api_log.rb
479
479
  - db/migrate/302_add_api_configs_validate_result.rb
480
+ - db/migrate/303_create_marty_logs.rb
480
481
  - db/seeds.rb
481
482
  - delorean/script_report.dl
482
483
  - gemini_deprecations.md