marty 1.0.43 → 1.0.44

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