liquid-ext 2.0.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +17 -25
  4. data/bin/liquid +2 -2
  5. data/lib/liquid/benchmark.rb +1 -1
  6. data/lib/liquid/boot.rb +53 -41
  7. data/lib/liquid/cli.rb +1 -6
  8. data/lib/liquid/configuration.rb +105 -122
  9. data/lib/liquid/{generator.rb → console.rb} +8 -1
  10. data/lib/liquid/ext/string.rb +8 -0
  11. data/lib/liquid/ext/thread.rb +6 -0
  12. data/lib/liquid/guava-16.0.1.jar +0 -0
  13. data/lib/liquid/health_checks.rb +4 -10
  14. data/lib/liquid/jeromq-0.3.3.jar +0 -0
  15. data/lib/liquid/kafka_2.10-0.8.0.jar +0 -0
  16. data/lib/liquid/log4j-1.2.17.jar +0 -0
  17. data/lib/liquid/logger.rb +122 -0
  18. data/lib/liquid/metrics/logger_reporter.rb +3 -6
  19. data/lib/liquid/metrics/reporter.rb +25 -13
  20. data/lib/liquid/metrics/tracker_reporter.rb +33 -0
  21. data/lib/liquid/metrics-annotation-2.2.0.jar +0 -0
  22. data/lib/liquid/metrics-core-2.2.0.jar +0 -0
  23. data/lib/liquid/metrics-core-3.0.1.jar +0 -0
  24. data/lib/liquid/metrics-healthchecks-3.0.1.jar +0 -0
  25. data/lib/liquid/metrics.rb +20 -21
  26. data/lib/liquid/router.rb +0 -1
  27. data/lib/liquid/scala-library-2.10.3.jar +0 -0
  28. data/lib/liquid/slf4j-api-1.7.6.jar +0 -0
  29. data/lib/liquid/slf4j-log4j12-1.7.6.jar +0 -0
  30. data/lib/liquid/snappy-java-1.1.1-M1.jar +0 -0
  31. data/lib/liquid/templates/config.yml.tt +0 -1
  32. data/lib/liquid/timing.rb +2 -10
  33. data/lib/liquid/tracker/base.rb +26 -0
  34. data/lib/liquid/tracker/blackhole_tracker.rb +15 -0
  35. data/lib/liquid/tracker/file_tracker.rb +21 -0
  36. data/lib/liquid/tracker/json_serializer.rb +13 -0
  37. data/lib/liquid/tracker/kafka_tracker.rb +41 -0
  38. data/lib/liquid/tracker/logger_tracker.rb +17 -0
  39. data/lib/liquid/tracker.rb +14 -0
  40. data/lib/liquid/transaction_id.rb +2 -2
  41. data/lib/liquid/trove-3.0.3.jar +0 -0
  42. data/lib/liquid/zmq.rb +89 -0
  43. data/liquid-ext.gemspec +1 -2
  44. data/spec/lib/liquid/router_spec.rb +6 -8
  45. data/spec/lib/liquid/weighted_selector_spec.rb +3 -1
  46. metadata +29 -34
  47. data/Jarfile +0 -2
  48. data/Jarfile.lock +0 -14
@@ -0,0 +1,122 @@
1
+ require 'liquid/ext/string'
2
+
3
+ require_relative './slf4j-api-1.7.6.jar'
4
+ require_relative './slf4j-log4j12-1.7.6.jar'
5
+ require_relative './log4j-1.2.17.jar'
6
+ java_import 'org.slf4j.LoggerFactory'
7
+
8
+ module Liquid
9
+ class Logger
10
+
11
+ attr_accessor :progname
12
+
13
+ def initialize(name, progname = nil)
14
+ @progname = progname || File.basename($0)
15
+ @logger = LoggerFactory.getLogger(name)
16
+ @exceptions = {}
17
+ root = org.apache.log4j.Logger.getRootLogger
18
+ appender = org.apache.log4j.ConsoleAppender.new
19
+ appender.name = "console"
20
+ appender.layout = org.apache.log4j.PatternLayout.new($conf.log.format)
21
+ appender.threshold = org.apache.log4j.Level.toLevel($conf.log.level.to_s)
22
+ appender.activateOptions
23
+ root.removeAllAppenders
24
+ root.addAppender(appender)
25
+ end
26
+
27
+ def trace?
28
+ @logger.trace_enabled?
29
+ end
30
+
31
+ def trace(*args, &block)
32
+ return unless trace?
33
+ args = yield if block_given?
34
+ @logger.trace(format(*args))
35
+ end
36
+
37
+ def debug?
38
+ @logger.debug_enabled?
39
+ end
40
+
41
+ def debug(*args, &block)
42
+ return unless debug?
43
+ args = yield if block_given?
44
+ @logger.debug(format(*args))
45
+ end
46
+
47
+ def info?
48
+ @logger.info_enabled?
49
+ end
50
+
51
+ def info(*args, &block)
52
+ return unless info?
53
+ args = yield if block_given?
54
+ @logger.info(format(*args))
55
+ end
56
+
57
+ def warn?
58
+ @logger.warn_enabled?
59
+ end
60
+
61
+ def warn(*args, &block)
62
+ return unless warn?
63
+ args = yield if block_given?
64
+ @logger.warn(format(*args))
65
+ end
66
+
67
+ def error?
68
+ @logger.error_enabled?
69
+ end
70
+
71
+ def error(*args, &block)
72
+ return unless error?
73
+ args = yield if block_given?
74
+ @logger.error(format(*args))
75
+ end
76
+
77
+ def exception(exc, message = nil, attribs = {})
78
+ ::Metrics.meter("exception:#{exc.class.to_s.tableize}").mark
79
+ @exceptions[exc.class] ||= {}
80
+ @exceptions[exc.class][exc.backtrace.first] ||= [System.nano_time, 1, 1]
81
+ five_minutes_ago = System.nano_time - 300_000_000_000
82
+ last, count, backoff = *@exceptions[exc.class][exc.backtrace.first]
83
+ count = backoff = 1 if last < five_minutes_ago
84
+ backoff = count > backoff ? backoff * 2 : backoff
85
+ if count % backoff == 0
86
+ error("exception", {
87
+ class: exc.class,
88
+ count: count,
89
+ reason: exc.message,
90
+ message: message,
91
+ backtrace: exc.backtrace
92
+ }.merge(attribs).merge(called_from))
93
+ end
94
+ @exceptions[exc.class][exc.backtrace.first] = [
95
+ System.nano_time,
96
+ count + 1,
97
+ backoff
98
+ ]
99
+ end
100
+
101
+ private
102
+
103
+ def format(message, attribs = {})
104
+ attribs.merge!(called_from) if $conf.log.caller
105
+ attribs = attribs.map do |k,v|
106
+ "#{k}=#{v.to_s.clean_quote}"
107
+ end.join(' ')
108
+ message += " #{attribs}" if attribs.length > 0
109
+ message
110
+ end
111
+
112
+ # Return the first callee outside the liquid-ext gem
113
+ def called_from
114
+ location = caller.detect('unknown:0') do |line|
115
+ line.match(/\/liquid(-|\/)ext/).nil?
116
+ end
117
+ file, line, _ = location.split(':')
118
+ { :file => file, :line => line }
119
+ end
120
+
121
+ end
122
+ end
@@ -3,13 +3,10 @@ require 'liquid/metrics/reporter'
3
3
  module Metrics
4
4
  class LoggerReporter < Reporter
5
5
 
6
- attr_accessor :logger
7
- attr_accessor :marker
8
-
9
- def initialize(registry)
6
+ def initialize(logger)
10
7
  super
11
- @logger = $log
12
- @marker = "metriks:"
8
+ @logger = logger
9
+ @marker = "metrics:"
13
10
  end
14
11
 
15
12
  def report_gauge(name, gauge)
@@ -11,12 +11,13 @@ module Metrics
11
11
  attr_accessor :rate_unit
12
12
  attr_accessor :duration_unit
13
13
 
14
- def initialize(registry)
15
- @registry = registry
14
+ def initialize(*args)
15
+ @registry = ::Metrics.registry
16
16
  @filter = MetricFilter::ALL
17
17
  @executor = Executors.newSingleThreadScheduledExecutor
18
18
  self.rate_unit = TimeUnit::SECONDS
19
19
  self.duration_unit = TimeUnit::MILLISECONDS
20
+ ::Metrics.register_reporter(self)
20
21
  end
21
22
 
22
23
  def rate_unit=(value)
@@ -39,9 +40,7 @@ module Metrics
39
40
  $log.exception(e)
40
41
  end
41
42
 
42
- def start(period = nil, unit = nil)
43
- period ||= 5
44
- unit ||= TimeUnit::MINUTES
43
+ def start(period = 60, unit = TimeUnit::SECONDS)
45
44
  @executor.scheduleAtFixedRate(self, period, period, unit)
46
45
  end
47
46
 
@@ -82,6 +81,7 @@ module Metrics
82
81
 
83
82
  def report_gauge(name, gauge)
84
83
  {
84
+ timestamp: Time.now.to_i,
85
85
  type: :gauge,
86
86
  name: name,
87
87
  value: gauge.value,
@@ -90,6 +90,7 @@ module Metrics
90
90
 
91
91
  def report_counter(name, counter)
92
92
  {
93
+ timestamp: Time.now.to_i,
93
94
  type: :counter,
94
95
  name: name,
95
96
  count: counter.count,
@@ -99,6 +100,7 @@ module Metrics
99
100
  def report_histogram(name, histogram)
100
101
  snapshot = histogram.snapshot
101
102
  {
103
+ timestamp: Time.now.to_i,
102
104
  type: :histogram,
103
105
  name: name,
104
106
  count: histogram.count,
@@ -107,25 +109,31 @@ module Metrics
107
109
  mean: snapshot.getMean,
108
110
  stdev: snapshot.getStdDev,
109
111
  median: snapshot.getMedian,
110
- :'95th_percentile' => snapshot.get95thPercentile,
112
+ p75: snapshot.get75thPercentile,
113
+ p95: snapshot.get95thPercentile,
114
+ p98: snapshot.get98thPercentile,
115
+ p99: snapshot.get99thPercentile,
116
+ p999: snapshot.get999thPercentile,
111
117
  }
112
118
  end
113
119
 
114
120
  def report_meter(name, meter)
115
121
  {
122
+ timestamp: Time.now.to_i,
116
123
  type: :meter,
117
124
  name: name,
118
125
  count: meter.count,
119
126
  mean_rate: convert_rate(meter.getMeanRate),
120
- one_minute_rate: convert_rate(meter.getOneMinuteRate),
121
- five_minute_rate: convert_rate(meter.getFiveMinuteRate),
122
- fifteen_minute_rate: convert_rate(meter.getFifteenMinuteRate),
127
+ m1: convert_rate(meter.getOneMinuteRate),
128
+ m5: convert_rate(meter.getFiveMinuteRate),
129
+ m15: convert_rate(meter.getFifteenMinuteRate),
123
130
  }
124
131
  end
125
132
 
126
133
  def report_timer(name, timer)
127
134
  snapshot = timer.snapshot
128
135
  {
136
+ timestamp: Time.now.to_i,
129
137
  type: :timer,
130
138
  name: name,
131
139
  min: convert_duration(snapshot.getMin),
@@ -133,11 +141,15 @@ module Metrics
133
141
  mean: convert_duration(snapshot.getMean),
134
142
  stdev: convert_duration(snapshot.getStdDev),
135
143
  median: convert_duration(snapshot.getMedian),
136
- :'95th_percentile' => convert_duration(snapshot.get95thPercentile),
144
+ p75: convert_duration(snapshot.get75thPercentile),
145
+ p95: convert_duration(snapshot.get95thPercentile),
146
+ p98: convert_duration(snapshot.get98thPercentile),
147
+ p99: convert_duration(snapshot.get99thPercentile),
148
+ p999: convert_duration(snapshot.get999thPercentile),
137
149
  mean_rate: convert_rate(timer.getMeanRate),
138
- one_minute_rate: convert_rate(timer.getOneMinuteRate),
139
- five_minute_rate: convert_rate(timer.getFiveMinuteRate),
140
- fifteen_minute_rate: convert_rate(timer.getFifteenMinuteRate),
150
+ m1: convert_rate(timer.getOneMinuteRate),
151
+ m5: convert_rate(timer.getFiveMinuteRate),
152
+ m15: convert_rate(timer.getFifteenMinuteRate),
141
153
  }
142
154
  end
143
155
 
@@ -0,0 +1,33 @@
1
+ require 'liquid/metrics/reporter'
2
+ require 'liquid/tracker'
3
+
4
+ module Metrics
5
+ class TrackerReporter < Reporter
6
+
7
+ def initialize(tracker)
8
+ super
9
+ @tracker = tracker
10
+ end
11
+
12
+ def report_gauge(name, gauge)
13
+ @tracker.event(super)
14
+ end
15
+
16
+ def report_counter(name, counter)
17
+ @tracker.event(super)
18
+ end
19
+
20
+ def report_histogram(name, histogram)
21
+ @tracker.event(super)
22
+ end
23
+
24
+ def report_meter(name, meter)
25
+ @tracker.event(super)
26
+ end
27
+
28
+ def report_timer(name, timer)
29
+ @tracker.event(super)
30
+ end
31
+
32
+ end
33
+ end
Binary file
Binary file
@@ -1,42 +1,41 @@
1
- require 'singleton'
1
+ require 'liquid/logger'
2
2
 
3
+ require_relative './metrics-core-3.0.1.jar'
3
4
  java_import 'com.codahale.metrics.Histogram'
4
- java_import 'com.codahale.metrics.MetricRegistry'
5
5
  java_import 'com.codahale.metrics.JmxReporter'
6
-
7
- require 'liquid/metrics/logger_reporter'
6
+ java_import 'com.codahale.metrics.MetricRegistry'
7
+ java_import 'java.util.concurrent.TimeUnit'
8
8
 
9
9
  class Histogram
10
10
  java_alias :update_long, :update, [Java::long]
11
11
  end
12
12
 
13
13
  module Metrics
14
-
15
- @@registry = MetricRegistry.new
16
- @@reporters = []
17
-
18
- def self.start
19
- @@reporters << JmxReporter.forRegistry(@@registry).build
20
- @@reporters << LoggerReporter.new(@@registry)
21
-
22
- @@reporters.each(&:start)
23
- Signal.register_shutdown_handler { self.stop }
14
+ @registry = MetricRegistry.new
15
+ @reporters = []
16
+
17
+ def self.start(period = nil, unit = nil)
18
+ @period ||= 60
19
+ @unit ||= TimeUnit::SECONDS
20
+ JmxReporter.forRegistry(@registry).build.start
21
+ Signal.register_shutdown_handler { stop }
24
22
  end
25
23
 
26
24
  def self.stop
27
- @@reporters.each do |reporter|
28
- if reporter.respond_to?(:run)
29
- reporter.run
30
- end
31
-
25
+ @reporters.each do |reporter|
26
+ reporter.run if reporter.respond_to?(:run)
32
27
  reporter.stop
33
28
  end
29
+ @reporters.clear
30
+ end
34
31
 
35
- @@reporters.clear
32
+ def self.register_reporter(reporter)
33
+ reporter.start(@period, @unit)
34
+ @reporters << reporter
36
35
  end
37
36
 
38
37
  def self.registry
39
- @@registry
38
+ @registry
40
39
  end
41
40
 
42
41
  def self.counter(name)
data/lib/liquid/router.rb CHANGED
@@ -41,6 +41,5 @@ class Router
41
41
 
42
42
  def handle(path, request)
43
43
  @cache[path].call(request) if @cache[path]
44
- return !! @cache[path]
45
44
  end
46
45
  end
Binary file
Binary file
Binary file
Binary file
@@ -1 +0,0 @@
1
- log_level: INFO
data/lib/liquid/timing.rb CHANGED
@@ -15,24 +15,16 @@ module Timing
15
15
  end
16
16
 
17
17
  def tick
18
- rt = runtime_since(@last_tick)
18
+ rt = System.nano_time - @last_tick
19
19
  @last_tick = System.nano_time
20
20
  rt
21
21
  end
22
22
 
23
23
  def stop
24
- rt = runtime_since(@start)
24
+ rt = System.nano_time - @start
25
25
  reset!
26
26
  rt
27
27
  end
28
28
 
29
- private
30
-
31
- def runtime_since(start)
32
- rt = System.nano_time - start
33
- rt = rt.to_f / 1_000_000_000
34
- rt
35
- end
36
-
37
29
  end
38
30
  end
@@ -0,0 +1,26 @@
1
+ require 'liquid/tracker/json_serializer'
2
+
3
+ module Tracker
4
+ class Base
5
+ attr_accessor :serializer
6
+
7
+ def initialize(dimensions = {})
8
+ @serializer = JsonSerializer.new(dimensions)
9
+ end
10
+
11
+ def with_topic(topic)
12
+ Topic.new(topic, self)
13
+ end
14
+ end
15
+
16
+ class Topic
17
+ def initialize(topic, tracker)
18
+ @topic = topic
19
+ @tracker = tracker
20
+ end
21
+
22
+ def event(obj)
23
+ @tracker.event(obj, @topic)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'liquid/tracker/base'
2
+
3
+ module Tracker
4
+ class BlackholeTracker < Base
5
+ def event(obj, topic)
6
+ end
7
+
8
+ def down?
9
+ false
10
+ end
11
+
12
+ def shutdown
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require 'liquid/tracker/base'
2
+
3
+ module Tracker
4
+ class FileTracker < Base
5
+
6
+ def event(obj, topic)
7
+ file = File.open(File.join(ROOT, 'log', "tracker-#{topic}.log"), 'a')
8
+ file.sync = true
9
+ file.write(@serializer.dump(obj))
10
+ file.write("\n")
11
+ file.close
12
+ end
13
+
14
+ def down?
15
+ false
16
+ end
17
+
18
+ def shutdown
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'multi_json'
2
+
3
+ module Tracker
4
+ class JsonSerializer
5
+ def initialize(dimensions)
6
+ @dimensions = dimensions
7
+ end
8
+
9
+ def dump(obj)
10
+ MultiJson.dump(@dimensions.merge(obj))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ require 'liquid/tracker/base'
2
+
3
+ require_relative '../scala-library-2.10.3.jar'
4
+ require_relative '../metrics-core-2.2.0.jar'
5
+ require_relative '../metrics-annotation-2.2.0.jar'
6
+ require_relative '../kafka_2.10-0.8.0.jar'
7
+ require_relative '../snappy-java-1.1.1-M1.jar'
8
+
9
+ module Tracker
10
+ class KafkaTracker < Base
11
+
12
+ java_import 'kafka.javaapi.producer.Producer'
13
+ java_import 'kafka.producer.ProducerConfig'
14
+ java_import 'kafka.producer.KeyedMessage'
15
+
16
+ def initialize(properties, dimensions = {})
17
+ super(dimensions)
18
+ @producer = Producer.new(ProducerConfig.new(properties))
19
+ end
20
+
21
+ def down?
22
+ # TODO: async is fire and forget. we might want to handle
23
+ # QueueFullExceptions later
24
+ false
25
+ end
26
+
27
+ def event(obj, topic)
28
+ @producer.send(KeyedMessage.new(topic, @serializer.dump(obj)))
29
+ rescue => e
30
+ # TODO: maybe fall back to FileTracker here
31
+ $log.exception(e, "failed to log event=#{obj.inspect}")
32
+ end
33
+
34
+ def shutdown
35
+ @producer.close if @producer
36
+ rescue Java::KafkaProducer::ProducerClosedException
37
+ # pass
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ require 'liquid/boot'
2
+ require 'liquid/tracker/base'
3
+
4
+ module Tracker
5
+ class LoggerTracker < Base
6
+ def event(obj, topic)
7
+ $log.info("tracker:event:#{topic} #{@serializer.dump(obj)}")
8
+ end
9
+
10
+ def down?
11
+ false
12
+ end
13
+
14
+ def shutdown
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'liquid/metrics'
2
+ require 'liquid/metrics/tracker_reporter'
3
+
4
+ module Tracker
5
+ class Metrics
6
+ def self.event
7
+ (@events ||= ::Metrics.meter("tracker.events")).mark
8
+ end
9
+ end
10
+ end
11
+
12
+ Dir[File.expand_path("../tracker/*.rb", __FILE__)].each do |f|
13
+ require f
14
+ end
@@ -6,8 +6,8 @@ class TransactionId
6
6
  @@current
7
7
  end
8
8
 
9
- def self.next
10
- @@current = "#{Time.now.to_i}-#{Process.pid}-#{rand(89999) + 10000}"
9
+ def self.next(seed = 10000)
10
+ @@current = "#{Time.now.to_i}-#{Process.pid}-#{rand(89999) + seed}"
11
11
  end
12
12
 
13
13
  end
Binary file
data/lib/liquid/zmq.rb ADDED
@@ -0,0 +1,89 @@
1
+ require_relative "./jeromq-0.3.3.jar"
2
+ java_import "org.zeromq.ZContext"
3
+ java_import "org.zeromq.ZFrame"
4
+ java_import "org.zeromq.ZLoop"
5
+ java_import "org.zeromq.ZMQ"
6
+ java_import "org.zeromq.ZMQException"
7
+ java_import "org.zeromq.ZMQQueue"
8
+ java_import "org.zeromq.ZMsg"
9
+ java_import "org.zeromq.ZThread"
10
+ java_import "java.nio.channels.ClosedSelectorException"
11
+
12
+ class ZContext
13
+ def create_socket_with_opts(type, opts = {})
14
+ socket = create_socket(type)
15
+ opts.each do |key, value|
16
+ next if key == :bind || key == :connect
17
+ socket.__send__("#{key}=", value)
18
+ end
19
+ socket.connect(opts[:connect]) if opts[:connect]
20
+ socket.bind(opts[:bind]) if opts[:bind]
21
+ socket
22
+ end
23
+
24
+ def router(opts = {})
25
+ create_socket_with_opts(ZMQ::ROUTER, opts)
26
+ end
27
+
28
+ def dealer(opts = {})
29
+ create_socket_with_opts(ZMQ::DEALER, opts)
30
+ end
31
+
32
+ def push(opts = {})
33
+ create_socket_with_opts(ZMQ::PUSH, opts)
34
+ end
35
+
36
+ def pull(opts = {})
37
+ create_socket_with_opts(ZMQ::PULL, opts)
38
+ end
39
+
40
+ def pub(opts = {})
41
+ create_socket_with_opts(ZMQ::PUB, opts)
42
+ end
43
+
44
+ def sub(opts = {})
45
+ create_socket_with_opts(ZMQ::SUB, opts)
46
+ end
47
+
48
+ ## global context instance
49
+
50
+ def self.instance
51
+ @context ||= new
52
+ end
53
+
54
+ def self.create_socket(type)
55
+ instance.create_socket(type)
56
+ end
57
+
58
+ def self.destroy_socket(socket)
59
+ instance.destroy_socket(socket)
60
+ end
61
+
62
+ def self.destroy
63
+ instance.destroy
64
+ end
65
+
66
+ def self.router(opts = {})
67
+ instance.router(opts)
68
+ end
69
+
70
+ def self.dealer(opts = {})
71
+ instance.dealer(opts)
72
+ end
73
+
74
+ def self.push(opts = {})
75
+ instance.push(opts)
76
+ end
77
+
78
+ def self.pull(opts = {})
79
+ instance.pull(opts)
80
+ end
81
+
82
+ def self.pub(opts = {})
83
+ instance.pub(opts)
84
+ end
85
+
86
+ def self.sub(opts = {})
87
+ instance.sub(opts)
88
+ end
89
+ end
data/liquid-ext.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "liquid-ext"
5
- spec.version = "2.0.3"
5
+ spec.version = "3.0.0"
6
6
  spec.authors = ["LiquidM, Inc."]
7
7
  spec.email = ["opensource@liquidm.com"]
8
8
  spec.description = %q{Ruby core extensions and helper libraries}
@@ -17,7 +17,6 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.add_dependency "activesupport"
19
19
  spec.add_dependency "erubis"
20
- spec.add_dependency "liquid-logging", ">= 2.0.0"
21
20
  spec.add_dependency "mixlib-cli"
22
21
  spec.add_dependency "terminal-table"
23
22
  end