aliyun-log 0.1.1 → 0.2.6

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
  SHA256:
3
- metadata.gz: 56b9e06d07673323179dae69adadfc8a6dc8518800181af620b31dfe13e5d11d
4
- data.tar.gz: 6d17a1f90049d299362b5fa8961b5a2befa56b93e12a07b4fb15fb65bdc914f0
3
+ metadata.gz: ed78b39497d6a671405b2d815292ca1e1e11ee301d816395264add76a9bc1235
4
+ data.tar.gz: 1b2f92c27745b27be61ca5f8fbb41470eaffcd710b22979671604173646c5450
5
5
  SHA512:
6
- metadata.gz: 265b850b91106ed251fbc1deda94b4f9138f4c055e703be864b99cbb156e3a90583d6da29b5f15e3a4210fd75e89470b7d5281d52573b6a0dd4d8ec6613006cb
7
- data.tar.gz: 7aca9990743677faa1863a34f2ce75bf66c357f6f177f8330de45a58ae7280ebaf6411856746b7566c64519f579ae37f5ef4e0ebd52253cf4a222ae348e90e07
6
+ metadata.gz: 19e6a18d2c168882054e14875da1baa18bab32217b2626a33e209e25c867b011deb5cba7d0b6de2f4af40a67ff4c66fb12ff3908881d9e28ced5ca8020c152b4
7
+ data.tar.gz: 7cfdddb1c6d804b4f62ee34cac200d4eb869ff32c70cf5bda5a4fd10947d06c5df61ba273662aff908a57e685a8ce2c586d1e3efed8d71e1dc2c8a59b649e117
@@ -9,11 +9,33 @@ require_relative 'log/protobuf'
9
9
  require_relative 'log/protocol'
10
10
  require_relative 'log/request'
11
11
  require_relative 'log/server_error'
12
+ require_relative 'log/record'
12
13
 
13
14
  module Aliyun
14
15
  module Log
15
- def self.configure
16
+ extend self
17
+
18
+ def configure
16
19
  block_given? ? yield(Config) : Config
17
20
  end
21
+ alias config configure
22
+
23
+ def included_models
24
+ @included_models ||= []
25
+ end
26
+
27
+ def record_connection
28
+ unless @record_connection
29
+ @record_connection = Protocol.new(Config.new)
30
+ end
31
+ @record_connection
32
+ end
33
+
34
+ def init_logstore
35
+ @included_models.each do |model|
36
+ model.create_logstore
37
+ modle.sync_index
38
+ end
39
+ end
18
40
  end
19
41
  end
@@ -31,6 +31,10 @@ module Aliyun
31
31
  def delete_project(name)
32
32
  @protocol.delete_project(name)
33
33
  end
34
+
35
+ def get_logstore(project_name, logstore_name)
36
+ @protocol.get_logstore(project_name, logstore_name)
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -38,7 +38,7 @@ module Aliyun
38
38
  def self.logger
39
39
  unless @logger
40
40
  @logger = Logger.new(
41
- @log_file ||= Config.log_file, MAX_NUM_LOG, ROTATE_SIZE
41
+ @log_file ||= Config.log_file || IO::NULL, MAX_NUM_LOG, ROTATE_SIZE
42
42
  )
43
43
  @logger.level = Logging.logger_level
44
44
  end
@@ -7,11 +7,12 @@ module Aliyun
7
7
  @endpoint = 'https://cn-beijing.log.aliyuncs.com'
8
8
  @open_timeout = 10
9
9
  @read_timeout = 120
10
- @log_file = 'aliyun_log.log'
11
10
  @log_level = Logger::DEBUG
11
+ @timestamps = true
12
12
  class << self
13
13
  attr_accessor :endpoint, :access_key_id, :access_key_secret,
14
- :open_timeout, :read_timeout, :log_file, :log_level
14
+ :open_timeout, :read_timeout, :log_file, :log_level,
15
+ :timestamps, :project
15
16
 
16
17
  def configure
17
18
  yield self
@@ -29,6 +30,7 @@ module Aliyun
29
30
  @access_key_secret ||= self.class.access_key_secret
30
31
  @endpoint ||= self.class.endpoint
31
32
  normalize_endpoint
33
+ raise 'Missing AccessKeyID or AccessKeySecret' if @access_key_id.nil? || @access_key_secret.nil?
32
34
  end
33
35
 
34
36
  private
@@ -30,13 +30,7 @@ module Aliyun
30
30
  end
31
31
 
32
32
  def put_log(attributes)
33
- contents = attributes.map { |k, v| { key: k.to_s, value: v.to_s } }
34
- log = Aliyun::Log::Protobuf::Log.new(
35
- time: Time.now.to_i,
36
- contents: contents
37
- )
38
- log_group = Aliyun::Log::Protobuf::LogGroup.new(logs: [log])
39
- put_logs(log_group)
33
+ @protocol.put_log(project_name, name, attributes)
40
34
  end
41
35
 
42
36
  def get_logs(opts = {})
@@ -66,7 +66,7 @@ module Aliyun
66
66
 
67
67
  def create_logstore(project_name, logstore_name, opt = {})
68
68
  body = {
69
- logstore_name: logstore_name,
69
+ logstoreName: logstore_name,
70
70
  ttl: opt[:ttl] || 365,
71
71
  shardCount: opt[:shard_count] || 2,
72
72
  autoSplit: opt[:auto_split].nil? ? false : opt[:auto_split],
@@ -105,10 +105,17 @@ module Aliyun
105
105
  @http.post({ project: project_name, logstore: logstore_name, is_pb: true }, content)
106
106
  end
107
107
 
108
- def put_log(project_name, logstore_name, log_attr)
109
- contents = log_attr.compact.map { |k, v| { key: k, value: v } }
110
- log_pb = Protobuf::Log.new(time: Time.now.to_i, contents: contents)
111
- lg_pb = Protobuf::LogGroup.new(logs: [log_pb])
108
+ def build_log_pb(attrs, time = Time.now.to_i)
109
+ logs = attrs.is_a?(Array) ? attrs : [attrs]
110
+ logs.map do |log_attr|
111
+ contents = log_attr.map { |k, v| { key: k, value: v.to_s } }
112
+ Protobuf::Log.new(time: time, contents: contents)
113
+ end
114
+ end
115
+
116
+ def put_log(project_name, logstore_name, logs, opts = {})
117
+ logs = build_log_pb(logs, opts[:time] || Time.now.to_i)
118
+ lg_pb = Protobuf::LogGroup.new(logs: logs, topic: opts[:topic])
112
119
  @http.post({ project: project_name, logstore: logstore_name, is_pb: true }, lg_pb)
113
120
  end
114
121
 
@@ -175,8 +182,8 @@ module Aliyun
175
182
  keys: {}
176
183
  }
177
184
  fields.each do |k, v|
185
+ v[:token] = INDEX_DEFAULT_TOKEN if %w[text json].include?(v[:type].to_s) && v[:token].nil?
178
186
  body[:keys][k] = v
179
- v[:token] = INDEX_DEFAULT_TOKEN if %w[text json].include?(v[:type]) && v[:token].blank?
180
187
  end
181
188
  @http.post({ project: project_name, logstore: logstore_name, action: 'index' }, body.to_json)
182
189
  end
@@ -189,8 +196,8 @@ module Aliyun
189
196
  keys: {}
190
197
  }
191
198
  fields.each do |k, v|
199
+ v[:token] = INDEX_DEFAULT_TOKEN if %w[text json].include?(v[:type].to_s) && v[:token].nil?
192
200
  body[:keys][k] = v
193
- v[:token] = INDEX_DEFAULT_TOKEN if v[:type] == 'text' && v[:token].blank?
194
201
  end
195
202
  @http.put({ project: project_name, logstore: logstore_name, action: 'index' }, body.to_json)
196
203
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/time'
5
+ require 'active_support/core_ext'
6
+ require 'active_model'
7
+ require 'forwardable'
8
+
9
+ require_relative 'record/exception'
10
+ require_relative 'record/field'
11
+ require_relative 'record/persistence'
12
+ require_relative 'record/relation'
13
+ require_relative 'record/scope_registry'
14
+
15
+ module Aliyun
16
+ module Log
17
+ module Record
18
+ extend ActiveSupport::Concern
19
+
20
+ included do
21
+ extend ActiveModel::Callbacks
22
+ include ActiveModel::Validations
23
+
24
+ class_attribute :options, instance_accessor: false, default: {}
25
+ class_attribute :base_class, instance_accessor: false, default: self
26
+ class_attribute :log_connection, instance_accessor: false
27
+ class_attribute :_schema_load, default: false
28
+
29
+ Log.included_models << self unless Log.included_models.include? self
30
+
31
+ field :created_at, :text if Config.timestamps
32
+
33
+ define_model_callbacks :save, :create, :initialize
34
+
35
+ before_save :set_created_at
36
+ end
37
+
38
+ include Field
39
+ include Persistence
40
+
41
+ include ActiveModel::AttributeMethods
42
+
43
+ module ClassMethods
44
+ def logstore(options = {})
45
+ opt = options.dup
46
+ if opt[:timestamps] && !Config.timestamps
47
+ field :created_at, :text
48
+ elsif opt[:timestamps] == false && Config.timestamps
49
+ remove_field :created_at
50
+ end
51
+ self._schema_load = true if opt[:auto_sync] == false
52
+ opt[:field_doc_value] = opt[:field_doc_value] != false
53
+ self.options = opt
54
+ end
55
+
56
+ delegate :load, :result, :count, to: :all
57
+ delegate :where, :query, :search, :sql, :from, :to, :page, :line, :limit, :offset, to: :all
58
+ delegate :first, :last, :second, :third, :fourth, :fifth, :find_offset, to: :all
59
+
60
+ def current_scope
61
+ ScopeRegistry.value_for(:current_scope, self)
62
+ end
63
+
64
+ def current_scope=(scope)
65
+ ScopeRegistry.set_value_for(:current_scope, self, scope)
66
+ end
67
+
68
+ def scope(name, body)
69
+ raise ArgumentError, 'The scope body needs to be callable.' unless body.respond_to?(:call)
70
+
71
+ singleton_class.send(:define_method, name) do |*args|
72
+ scope = all
73
+ scope = scope.scoping { body.call(*args) }
74
+ scope
75
+ end
76
+ end
77
+
78
+ def all
79
+ scope = current_scope
80
+ scope ||= relation.from(0).to(Time.now.to_i)
81
+ scope
82
+ end
83
+
84
+ private
85
+
86
+ def relation
87
+ Relation.new(self)
88
+ end
89
+ end
90
+
91
+ def initialize(attrs = {})
92
+ run_callbacks :initialize do
93
+ @new_record = true
94
+ @attributes ||= {}
95
+
96
+ attrs_with_defaults = self.class.attributes.each_with_object({}) do |(attribute, options), res|
97
+ res[attribute] = if attrs.key?(attribute)
98
+ attrs[attribute]
99
+ elsif options.key?(:default)
100
+ evaluate_default_value(options[:default])
101
+ end
102
+ end
103
+
104
+ attrs_virtual = attrs.slice(*(attrs.keys - self.class.attributes.keys))
105
+
106
+ attrs_with_defaults.merge(attrs_virtual).each do |key, value|
107
+ if respond_to?("#{key}=")
108
+ send("#{key}=", value)
109
+ else
110
+ raise UnknownAttributeError, "unknown attribute '#{key}' for #{@record.class}."
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ def inspect
117
+ inspection = if defined?(@attributes) && @attributes
118
+ self.class.attributes.keys.collect do |name|
119
+ "#{name}: #{attribute_for_inspect(name)}" if has_attribute?(name)
120
+ end.compact.join(', ')
121
+ else
122
+ 'not initialized'
123
+ end
124
+
125
+ "#<#{self.class} #{inspection}>"
126
+ end
127
+
128
+ def attribute_for_inspect(attr_name)
129
+ value = read_attribute(attr_name)
130
+
131
+ if value.is_a?(String) && value.length > 50
132
+ "#{value[0, 50]}...".inspect
133
+ elsif value.is_a?(Date) || value.is_a?(Time)
134
+ %("#{value.to_s(:db)}")
135
+ else
136
+ value.inspect
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,9 @@
1
+ module Aliyun
2
+ module Log
3
+ module Record
4
+ class ArgumentError < StandardError; end
5
+ class UnknownAttributeError < StandardError; end
6
+ class ProjectNameError < StandardError; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aliyun
4
+ module Log
5
+ module Record
6
+ module Field
7
+ extend ActiveSupport::Concern
8
+
9
+ # Types allowed in indexes:
10
+ PERMITTED_KEY_TYPES = %i[
11
+ text
12
+ long
13
+ double
14
+ json
15
+ ].freeze
16
+
17
+ DEFAULT_INDEX_TOKEN = ", '\";=()[]{}?@&<>/:\n\t\r".split('')
18
+
19
+ included do
20
+ class_attribute :attributes, instance_accessor: false, default: {}
21
+ end
22
+
23
+ module ClassMethods
24
+ def field(name, type = :text, options = {})
25
+ unless PERMITTED_KEY_TYPES.include?(type)
26
+ raise ArgumentError, "Field #{name} type(#{type}) error, key type only support text/long/double/json"
27
+ end
28
+
29
+ named = name.to_s
30
+ self.attributes = attributes.merge(name => { type: type }.merge(options))
31
+
32
+ warn_about_method_overriding(name, name)
33
+ warn_about_method_overriding("#{named}=", name)
34
+ warn_about_method_overriding("#{named}?", name)
35
+
36
+ define_attribute_method(name) # Dirty API
37
+
38
+ generated_methods.module_eval do
39
+ define_method(named) { read_attribute(named) }
40
+ define_method("#{named}?") do
41
+ value = read_attribute(named)
42
+ case value
43
+ when true then true
44
+ when false, nil then false
45
+ else
46
+ !value.nil?
47
+ end
48
+ end
49
+ define_method("#{named}=") { |value| write_attribute(named, value) }
50
+ end
51
+ end
52
+
53
+ def remove_field(field)
54
+ field = field.to_sym
55
+ attributes.delete(field) || raise('No such field')
56
+
57
+ undefine_attribute_methods
58
+ define_attribute_methods attributes.keys
59
+
60
+ generated_methods.module_eval do
61
+ remove_method field
62
+ remove_method :"#{field}="
63
+ remove_method :"#{field}?"
64
+ remove_method :"#{field}_before_type_cast"
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def generated_methods
71
+ @generated_methods ||= begin
72
+ Module.new.tap do |mod|
73
+ include(mod)
74
+ end
75
+ end
76
+ end
77
+
78
+ def warn_about_method_overriding(method_name, field_name)
79
+ if instance_methods.include?(method_name.to_sym)
80
+ Common::Logging.logger.warn("Method #{method_name} generated for the field #{field_name} overrides already existing method")
81
+ end
82
+ end
83
+ end
84
+
85
+ def attribute_names
86
+ @attributes.keys
87
+ end
88
+
89
+ def has_attribute?(attr_name)
90
+ @attributes.key?(attr_name.to_sym)
91
+ end
92
+
93
+ def evaluate_default_value(val)
94
+ if val.respond_to?(:call)
95
+ val.call
96
+ elsif val.duplicable?
97
+ val.dup
98
+ else
99
+ val
100
+ end
101
+ end
102
+
103
+ attr_accessor :attributes
104
+
105
+ def write_attribute(name, value)
106
+ attributes[name.to_sym] = value
107
+ end
108
+
109
+ alias []= write_attribute
110
+
111
+ def read_attribute(name)
112
+ attributes[name.to_sym]
113
+ end
114
+ alias [] read_attribute
115
+
116
+ def set_created_at
117
+ self.created_at ||= DateTime.now.in_time_zone(Time.zone).to_s if timestamps_enabled?
118
+ end
119
+
120
+ def timestamps_enabled?
121
+ self.class.options[:timestamps] || (self.class.options[:timestamps].nil? && Config.timestamps)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aliyun
4
+ module Log
5
+ module Record
6
+ module Persistence
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def logstore_name
11
+ @logstore_name ||= options[:name] ||
12
+ base_class.name.split('::').last.underscore.pluralize
13
+ end
14
+
15
+ def logstore_name=(value)
16
+ if defined?(@logstore_name)
17
+ return if value == @logstore_name
18
+ end
19
+
20
+ @logstore_name = value
21
+ end
22
+
23
+ def project_name
24
+ unless @project_name
25
+ @project_name = options[:project] || Config.project
26
+ raise ProjectNameError, "project can't be empty" if @project_name.blank?
27
+ end
28
+ @project_name
29
+ end
30
+
31
+ def create_logstore(options = {})
32
+ Log.record_connection.get_logstore(project_name, logstore_name)
33
+ rescue ServerError => e
34
+ Log.record_connection.create_logstore(project_name, logstore_name, options)
35
+ end
36
+
37
+ def sync_index
38
+ has_index? ? update_index : create_index
39
+ end
40
+
41
+ def auto_load_schema
42
+ return if _schema_load
43
+
44
+ create_logstore
45
+ sync_index
46
+ self._schema_load = true
47
+ end
48
+
49
+ def has_index?
50
+ Log.record_connection.get_index(project_name, logstore_name)
51
+ true
52
+ rescue ServerError
53
+ false
54
+ end
55
+
56
+ def create(data, opts = {})
57
+ auto_load_schema
58
+ if data.is_a?(Array)
59
+ logs = []
60
+ data.each do |log_attr|
61
+ logs << new(log_attr).save_array
62
+ end
63
+ res = Log.record_connection.put_log(project_name, logstore_name, logs, opts)
64
+ res.code == 200
65
+ else
66
+ new(data).save
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def evaluate_default_value(val)
73
+ if val.respond_to?(:call)
74
+ val.call
75
+ elsif val.duplicable?
76
+ val.dup
77
+ else
78
+ val
79
+ end
80
+ end
81
+
82
+ def field_indices
83
+ indices = if options[:field_index] == false
84
+ attributes.select { |_, value| value[:index] == true }
85
+ else
86
+ attributes.reject { |_, value| value[:index] == false }
87
+ end
88
+ indices.each do |_, v|
89
+ next unless v[:doc_value].nil?
90
+
91
+ v[:doc_value] = options[:field_doc_value] != false
92
+ end
93
+ indices
94
+ end
95
+
96
+ def create_index
97
+ Log.record_connection.create_index(
98
+ project_name,
99
+ logstore_name,
100
+ field_indices
101
+ )
102
+ end
103
+
104
+ def update_index
105
+ conf_res = Log.record_connection.get_index(project_name, logstore_name)
106
+ raw_conf = JSON.parse(conf_res)
107
+ index_conf = raw_conf.dup
108
+ field_indices.each do |k, v|
109
+ index_conf['keys'][k.to_s] ||= v
110
+ end
111
+ return if index_conf['keys'] == raw_conf['keys']
112
+
113
+ Log.record_connection.update_index(
114
+ project_name,
115
+ logstore_name,
116
+ index_conf['keys']
117
+ )
118
+ end
119
+ end
120
+
121
+ def save
122
+ self.class.auto_load_schema
123
+ run_callbacks(:create) do
124
+ run_callbacks(:save) do
125
+ if valid?
126
+ res = Log.record_connection.put_log(self.class.project_name, self.class.logstore_name, attributes)
127
+ res.code == 200
128
+ else
129
+ false
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def save_array
136
+ run_callbacks(:create) do
137
+ run_callbacks(:save) do
138
+ validate! && attributes
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aliyun
4
+ module Log
5
+ module Record
6
+ class Relation
7
+ def initialize(klass, opts = {})
8
+ @klass = klass
9
+ @opts = opts
10
+ @klass.auto_load_schema
11
+ @opts[:search] ||= '*'
12
+ end
13
+
14
+ def inspect
15
+ "#<#{self.class}>"
16
+ end
17
+
18
+ def first(line = 1)
19
+ find_offset(0, line, false)
20
+ end
21
+
22
+ def second
23
+ find_offset(1)
24
+ end
25
+
26
+ def third
27
+ find_offset(2)
28
+ end
29
+
30
+ def fourth
31
+ find_offset(3)
32
+ end
33
+
34
+ def fifth
35
+ find_offset(4)
36
+ end
37
+
38
+ def last(line = 1)
39
+ find_offset(0, line, true)
40
+ end
41
+
42
+ def find_offset(nth, line = 1, reverse = false)
43
+ @opts[:line] = line
44
+ @opts[:offset] = nth
45
+ @opts[:reverse] = reverse
46
+ line <= 1 ? load[0] : load
47
+ end
48
+
49
+ def scoping
50
+ previous = @klass.current_scope
51
+ @klass.current_scope = self
52
+ yield
53
+ ensure
54
+ @klass.current_scope = previous
55
+ end
56
+
57
+ def from(from)
58
+ ts = from.is_a?(Integer) ? from : from.to_time.to_i
59
+ @opts[:from] = ts
60
+ self
61
+ end
62
+
63
+ def to(to)
64
+ ts = to.is_a?(Integer) ? to : to.to_time.to_i
65
+ @opts[:to] = ts
66
+ self
67
+ end
68
+
69
+ def line(val)
70
+ @opts[:line] = val.to_i
71
+ self
72
+ end
73
+ alias limit line
74
+
75
+ def offset(val)
76
+ @opts[:offset] = val.to_i
77
+ self
78
+ end
79
+
80
+ def page(val)
81
+ @opts[:page] = val - 1 if val >= 1
82
+ self
83
+ end
84
+
85
+ def where(opts)
86
+ @opts.merge!(opts)
87
+ self
88
+ end
89
+
90
+ def search(str)
91
+ @opts[:search] = str
92
+ self
93
+ end
94
+
95
+ def sql(str)
96
+ @opts[:sql] = str
97
+ self
98
+ end
99
+
100
+ def query(opts = {})
101
+ @opts[:query] = opts
102
+ self
103
+ end
104
+
105
+ def count
106
+ query = @opts.dup
107
+ if query[:query].blank?
108
+ where_cond = query[:sql].split(/where /i)[1] if query[:sql].present?
109
+ query[:query] = "#{query[:search]}|SELECT COUNT(*) as count"
110
+ query[:query] = "#{query[:query]} WHERE #{where_cond}" if where_cond.present?
111
+ end
112
+ res = Log.record_connection.get_logs(@klass.project_name, @klass.logstore_name, query)
113
+ res = JSON.parse(res.body)
114
+ res[0]['count'].to_i
115
+ end
116
+
117
+ def result
118
+ query = @opts.dup
119
+ if query[:page]
120
+ query[:line] ||= 100
121
+ query[:offset] = query[:page] * query[:line]
122
+ end
123
+ query[:query] = query[:search]
124
+ query[:query] = "#{query[:query]}|#{query[:sql]}" if query[:sql].present?
125
+ res = Log.record_connection.get_logs(@klass.project_name, @klass.logstore_name, query)
126
+ JSON.parse(res)
127
+ end
128
+
129
+ def load
130
+ result.map do |json_attr|
131
+ attrs = {}
132
+ @klass.attributes.keys.each do |k, _|
133
+ attrs[k] = json_attr[k.to_s]
134
+ end
135
+ @klass.new(attrs)
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def method_missing(method, *args, &block)
142
+ if @klass.respond_to?(method)
143
+ scoping { @klass.public_send(method, *args, &block) }
144
+ else
145
+ super
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aliyun
4
+ module Log
5
+ module PerThreadRegistry
6
+ def self.extended(object)
7
+ object.instance_variable_set '@per_thread_registry_key', object.name.freeze
8
+ end
9
+
10
+ def instance
11
+ Thread.current[@per_thread_registry_key] ||= new
12
+ end
13
+
14
+ private
15
+
16
+ def method_missing(name, *args, &block)
17
+ singleton_class.delegate name, to: :instance
18
+
19
+ send(name, *args, &block)
20
+ end
21
+ end
22
+
23
+ class ScopeRegistry
24
+ extend PerThreadRegistry
25
+
26
+ def initialize
27
+ @registry = Hash.new { |hash, key| hash[key] = {} }
28
+ end
29
+
30
+ def value_for(scope_type, model)
31
+ @registry[scope_type][model.name]
32
+ end
33
+
34
+ # Sets the +value+ for a given +scope_type+ and +model+.
35
+ def set_value_for(scope_type, model, value)
36
+ @registry[scope_type][model.name] = value
37
+ end
38
+ end
39
+ end
40
+ end
@@ -20,10 +20,10 @@ module Aliyun
20
20
  resources ||= {}
21
21
  res = '/'
22
22
  if resources[:logstore]
23
- res << 'logstores'
24
- res << "/#{resources[:logstore]}" unless resources[:logstore].empty?
23
+ res = "#{res}logstores"
24
+ res = "#{res}/#{resources[:logstore]}" unless resources[:logstore].empty?
25
25
  end
26
- res << "/#{resources[:action]}" if resources[:action]
26
+ res = "#{res}/#{resources[:action]}" if resources[:action]
27
27
  res
28
28
  end
29
29
 
@@ -53,24 +53,21 @@ module Aliyun
53
53
 
54
54
  def do_request(verb, resources, payload)
55
55
  resource_path = get_resource_path(resources)
56
- headers = {}
57
- if verb == 'GET'
58
- headers = compact_headers
59
- headers['Authorization'] = signature(verb, resource_path, headers, payload)
60
- else
61
- headers = compact_headers(payload, resources[:is_pb])
62
- headers['Authorization'] = signature(verb, resource_path, headers)
63
- end
64
56
  request_options = {
65
57
  method: verb,
66
58
  url: get_request_url(resources),
67
- headers: headers,
68
59
  open_timeout: @config.open_timeout,
69
60
  read_timeout: @config.read_timeout
70
61
  }
71
62
  if verb == 'GET'
72
- request_options[:url] = canonicalized_resource(request_options[:url], payload)
63
+ headers = compact_headers
64
+ headers['Authorization'] = signature(verb, resource_path, headers, payload)
65
+ request_options[:headers] = headers
66
+ request_options[:url] = URI.escape(canonicalized_resource(request_options[:url], payload))
73
67
  else
68
+ headers = compact_headers(payload, resources[:is_pb])
69
+ headers['Authorization'] = signature(verb, resource_path, headers)
70
+ request_options[:headers] = headers
74
71
  payload = Zlib::Deflate.deflate(payload.encode) if resources[:is_pb]
75
72
  request_options[:payload] = payload
76
73
  end
@@ -86,7 +83,7 @@ module Aliyun
86
83
  end
87
84
 
88
85
  logger.debug("Received HTTP response, code: #{response.code}, headers: " \
89
- "#{response.headers}, body: #{response.body}")
86
+ "#{response.headers}, body: #{response.body.force_encoding('UTF-8')}")
90
87
 
91
88
  response
92
89
  end
@@ -104,7 +101,6 @@ module Aliyun
104
101
  if is_pb
105
102
  compressed = Zlib::Deflate.deflate(body.encode)
106
103
  headers['Content-Length'] = compressed.bytesize.to_s
107
- # 日志内容包含的日志必须小于3MB和4096条。
108
104
  raise 'content length is larger than 3MB' if headers['Content-Length'].to_i > 3_145_728
109
105
 
110
106
  headers['Content-MD5'] = Digest::MD5.hexdigest(compressed).upcase
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Aliyun
4
4
  module Log
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.6'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aliyun-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yingce Liu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: protobuf
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -30,14 +58,14 @@ dependencies:
30
58
  requirements:
31
59
  - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: 2.1.0
61
+ version: 2.0.0
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: 2.1.0
68
+ version: 2.0.0
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: bundler
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,7 +114,7 @@ dependencies:
86
114
  - - "~>"
87
115
  - !ruby/object:Gem::Version
88
116
  version: '3.0'
89
- description: Aliyun Log SDK for Ruby 阿里云日志服务(SLS) Ruby SDK, 目前仅实现基于Restfull部分接口
117
+ description: Aliyun Log SDK for Ruby 阿里云日志服务(SLS) Ruby SDK, 目前仅实现基于Restfull部分接口和简单Model映射
90
118
  email:
91
119
  - yingce@live.com
92
120
  executables: []
@@ -103,6 +131,12 @@ files:
103
131
  - lib/aliyun/log/project.rb
104
132
  - lib/aliyun/log/protobuf.rb
105
133
  - lib/aliyun/log/protocol.rb
134
+ - lib/aliyun/log/record.rb
135
+ - lib/aliyun/log/record/exception.rb
136
+ - lib/aliyun/log/record/field.rb
137
+ - lib/aliyun/log/record/persistence.rb
138
+ - lib/aliyun/log/record/relation.rb
139
+ - lib/aliyun/log/record/scope_registry.rb
106
140
  - lib/aliyun/log/request.rb
107
141
  - lib/aliyun/log/server_error.rb
108
142
  - lib/aliyun/version.rb