aliyun-log 0.2.8 → 0.2.13
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 +4 -4
- data/lib/aliyun/log.rb +1 -0
- data/lib/aliyun/log/protobuf.rb +6 -0
- data/lib/aliyun/log/record.rb +11 -2
- data/lib/aliyun/log/record/field.rb +6 -1
- data/lib/aliyun/log/record/persistence.rb +80 -34
- data/lib/aliyun/log/record/relation.rb +186 -28
- data/lib/aliyun/log/record/scoping.rb +4 -3
- data/lib/aliyun/log/record/type_casting.rb +34 -3
- data/lib/aliyun/log/request.rb +10 -24
- data/lib/aliyun/log/utils.rb +29 -0
- data/lib/aliyun/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d6574ee8e72a65c178f4cdc28c61e63379999e51166c95756b9ffd6b367f47a
|
4
|
+
data.tar.gz: 8fdce159cd971c94c966b20db9926653a16e4bd5efaee918f619a6f0bf00a9e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ce9aed0a16e0c0a47fe8baadc45215967fd33cef33bece8bdfca0148a565155f347860d3bf986091b965419e04d513e19756c87b6f52ac32879188f07f3a11
|
7
|
+
data.tar.gz: f7c441bdb8ae2f3a768b236fb1bc8b86ad0c4965324b9323142565d50ed776b632ff11ba2036af7b1d1058968daeabe14080f792cbf2d438c777a6f4a25f17cf
|
data/lib/aliyun/log.rb
CHANGED
data/lib/aliyun/log/protobuf.rb
CHANGED
@@ -16,11 +16,17 @@ module Aliyun
|
|
16
16
|
repeated Content, :contents, 2
|
17
17
|
end
|
18
18
|
|
19
|
+
class LogTag < ::Protobuf::Message
|
20
|
+
required :string, :key, 1
|
21
|
+
required :string, :value, 2
|
22
|
+
end
|
23
|
+
|
19
24
|
class LogGroup < ::Protobuf::Message
|
20
25
|
repeated Log, :logs, 1
|
21
26
|
optional :string, :reserved, 2
|
22
27
|
optional :string, :topic, 3
|
23
28
|
optional :string, :source, 4
|
29
|
+
repeated LogTag, :log_tags, 6
|
24
30
|
end
|
25
31
|
end
|
26
32
|
end
|
data/lib/aliyun/log/record.rb
CHANGED
@@ -4,7 +4,7 @@ require 'active_support'
|
|
4
4
|
require 'active_support/time'
|
5
5
|
require 'active_support/core_ext'
|
6
6
|
require 'active_model'
|
7
|
-
require '
|
7
|
+
require 'monitor'
|
8
8
|
|
9
9
|
require_relative 'record/exception'
|
10
10
|
require_relative 'record/field'
|
@@ -22,16 +22,21 @@ module Aliyun
|
|
22
22
|
|
23
23
|
class_attribute :options, instance_accessor: false, default: {}
|
24
24
|
class_attribute :base_class, instance_accessor: false, default: self
|
25
|
-
class_attribute :log_connection, instance_accessor: false
|
26
25
|
class_attribute :_schema_load, default: false
|
27
26
|
|
28
27
|
Log.included_models << self unless Log.included_models.include? self
|
29
28
|
|
29
|
+
field :__time__, type: :long, cast_type: :integer
|
30
|
+
field :__topic__
|
31
|
+
field :__source__
|
32
|
+
|
30
33
|
field :created_at, type: :text, cast_type: :datetime if Config.timestamps
|
31
34
|
|
32
35
|
define_model_callbacks :save, :create, :initialize
|
33
36
|
|
34
37
|
before_save :set_created_at
|
38
|
+
|
39
|
+
@lock = Monitor.new
|
35
40
|
end
|
36
41
|
|
37
42
|
include Field
|
@@ -79,6 +84,10 @@ module Aliyun
|
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
87
|
+
def new_record?
|
88
|
+
@new_record == true
|
89
|
+
end
|
90
|
+
|
82
91
|
def inspect
|
83
92
|
inspection = if defined?(@attributes) && @attributes
|
84
93
|
self.class.attributes.keys.collect do |name|
|
@@ -20,6 +20,7 @@ module Aliyun
|
|
20
20
|
|
21
21
|
included do
|
22
22
|
class_attribute :attributes, instance_accessor: false, default: {}
|
23
|
+
class_attribute :tag_attributes, instance_accessor: false, default: {}
|
23
24
|
extend Common::Logging
|
24
25
|
end
|
25
26
|
|
@@ -31,7 +32,11 @@ module Aliyun
|
|
31
32
|
end
|
32
33
|
|
33
34
|
named = name.to_s
|
34
|
-
|
35
|
+
if options[:log_tag]
|
36
|
+
self.tag_attributes = tag_attributes.merge(name => { type: type }.merge(options))
|
37
|
+
else
|
38
|
+
self.attributes = attributes.merge(name => { type: type }.merge(options))
|
39
|
+
end
|
35
40
|
|
36
41
|
warn_about_method_overriding(name, name)
|
37
42
|
warn_about_method_overriding("#{named}=", name)
|
@@ -4,6 +4,14 @@ module Aliyun
|
|
4
4
|
module Log
|
5
5
|
module Record
|
6
6
|
module Persistence
|
7
|
+
RESERVED_FIELDS = %i[
|
8
|
+
__time__
|
9
|
+
__topic__
|
10
|
+
__source__
|
11
|
+
__partition_time__
|
12
|
+
__extract_others__
|
13
|
+
].freeze
|
14
|
+
|
7
15
|
extend ActiveSupport::Concern
|
8
16
|
|
9
17
|
module ClassMethods
|
@@ -35,15 +43,17 @@ module Aliyun
|
|
35
43
|
end
|
36
44
|
|
37
45
|
def sync_index
|
46
|
+
return if field_indices.blank?
|
38
47
|
has_index? ? update_index : create_index
|
39
48
|
end
|
40
49
|
|
41
50
|
def auto_load_schema
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
@lock.synchronize do
|
52
|
+
return if _schema_load
|
53
|
+
create_logstore
|
54
|
+
sync_index
|
55
|
+
self._schema_load = true
|
56
|
+
end
|
47
57
|
end
|
48
58
|
|
49
59
|
def has_index?
|
@@ -53,19 +63,23 @@ module Aliyun
|
|
53
63
|
false
|
54
64
|
end
|
55
65
|
|
56
|
-
def create(data,
|
66
|
+
def create(data, force = false)
|
57
67
|
auto_load_schema
|
58
68
|
if data.is_a?(Array)
|
59
|
-
|
60
|
-
|
69
|
+
# TODO batch insert
|
70
|
+
data.each do |log|
|
71
|
+
saved = new(log).save(force)
|
72
|
+
return false unless saved
|
61
73
|
end
|
62
|
-
res = Log.record_connection.put_log(project_name, logstore_name, logs, opts)
|
63
|
-
res.code == 200
|
64
74
|
else
|
65
|
-
new(data).save
|
75
|
+
new(data).save(force)
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
79
|
+
def create!(data)
|
80
|
+
create(data, true)
|
81
|
+
end
|
82
|
+
|
69
83
|
private
|
70
84
|
|
71
85
|
def evaluate_default_value(val)
|
@@ -79,11 +93,12 @@ module Aliyun
|
|
79
93
|
end
|
80
94
|
|
81
95
|
def field_indices
|
82
|
-
if options[:field_index] == false
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
96
|
+
indices = if options[:field_index] == false
|
97
|
+
attributes.select { |_, value| value[:index] == true }
|
98
|
+
else
|
99
|
+
attributes.reject { |_, value| value[:index] == false }
|
100
|
+
end
|
101
|
+
indices.reject { |key, _| RESERVED_FIELDS.include?(key) }
|
87
102
|
end
|
88
103
|
|
89
104
|
def create_index
|
@@ -99,6 +114,7 @@ module Aliyun
|
|
99
114
|
raw_conf = JSON.parse(conf_res)
|
100
115
|
index_conf = raw_conf.deep_dup
|
101
116
|
field_index_types.each do |k, v|
|
117
|
+
index_conf['keys'] ||= {}
|
102
118
|
index_conf['keys'][k.to_s] ||= {}
|
103
119
|
index_conf['keys'][k.to_s].merge!(v.as_json)
|
104
120
|
end
|
@@ -123,38 +139,68 @@ module Aliyun
|
|
123
139
|
end
|
124
140
|
end
|
125
141
|
|
142
|
+
def dump_log_tags
|
143
|
+
log_tags = {}
|
144
|
+
self.class.tag_attributes.map do |key, options|
|
145
|
+
log_tags[key] = TypeCasting.dump_field(attributes[key], options)
|
146
|
+
end
|
147
|
+
log_tags.compact
|
148
|
+
end
|
149
|
+
|
126
150
|
def dump_attributes
|
127
151
|
attributes.dup.tap do |tap|
|
128
152
|
tap.each do |k, v|
|
129
|
-
|
153
|
+
if self.class.attributes[k][:log_tag] || RESERVED_FIELDS.include?(k)
|
154
|
+
tap.delete(k)
|
155
|
+
else
|
156
|
+
tap[k] = TypeCasting.dump_field(v, self.class.attributes[k])
|
157
|
+
end
|
130
158
|
end
|
131
159
|
end
|
132
160
|
end
|
133
161
|
|
134
|
-
def save
|
162
|
+
def save(force = false)
|
135
163
|
self.class.auto_load_schema
|
136
164
|
run_callbacks(:create) do
|
137
165
|
run_callbacks(:save) do
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
)
|
144
|
-
res.code == 200
|
145
|
-
else
|
146
|
-
false
|
147
|
-
end
|
166
|
+
force && validate!
|
167
|
+
return false unless valid?
|
168
|
+
saved = put_logs
|
169
|
+
@new_record = false if saved
|
170
|
+
saved
|
148
171
|
end
|
149
172
|
end
|
150
173
|
end
|
151
174
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
175
|
+
def save!
|
176
|
+
save(true)
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def put_logs
|
182
|
+
log_tags = []
|
183
|
+
dump_log_tags.each do |k, v|
|
184
|
+
log_tags << Protobuf::LogTag.new(key: k, value: v)
|
185
|
+
end
|
186
|
+
lg = Protobuf::LogGroup.new(
|
187
|
+
logs: [generate_log],
|
188
|
+
log_tags: log_tags,
|
189
|
+
topic: read_attribute(:__topic__),
|
190
|
+
source: read_attribute(:__source__)
|
191
|
+
)
|
192
|
+
res = Log.record_connection.put_logs(
|
193
|
+
self.class.project_name,
|
194
|
+
self.class.logstore_name,
|
195
|
+
lg
|
196
|
+
)
|
197
|
+
res.code == 200
|
198
|
+
end
|
199
|
+
|
200
|
+
def generate_log
|
201
|
+
time = read_attribute(:__time__) || Time.now.to_i
|
202
|
+
contents = dump_attributes.map { |k, v| { key: k, value: v.to_s } }
|
203
|
+
Protobuf::Log.new(time: time, contents: contents)
|
158
204
|
end
|
159
205
|
end
|
160
206
|
end
|
@@ -10,9 +10,9 @@ module Aliyun
|
|
10
10
|
@klass.auto_load_schema
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def inspect
|
14
|
+
"#<#{self.class}>"
|
15
|
+
end
|
16
16
|
|
17
17
|
def first(line = 1)
|
18
18
|
find_offset(0, line, false)
|
@@ -35,14 +35,28 @@ module Aliyun
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def last(line = 1)
|
38
|
-
find_offset(0, line, true)
|
38
|
+
data = find_offset(0, line, true)
|
39
|
+
line > 1 ? data.reverse : data
|
39
40
|
end
|
40
41
|
|
41
42
|
def find_offset(nth, line = 1, reverse = false)
|
43
|
+
# @opts[:select] = '*'
|
42
44
|
@opts[:line] = line
|
43
45
|
@opts[:offset] = nth
|
44
|
-
@opts[:
|
45
|
-
|
46
|
+
if @opts[:order].present? && reverse
|
47
|
+
conds = []
|
48
|
+
@opts[:order].split(',').each do |field|
|
49
|
+
field.gsub!(/\s+desc|asc.*/i, '')
|
50
|
+
conds << "#{field.strip} DESC"
|
51
|
+
end
|
52
|
+
@opts[:order] = conds.join(', ')
|
53
|
+
end
|
54
|
+
@opts[:order] ||= reverse ? '__time__ DESC' : '__time__ ASC'
|
55
|
+
if @opts[:select].blank?
|
56
|
+
line <= 1 ? load[0] : load
|
57
|
+
else
|
58
|
+
line <= 1 ? result[0] : result
|
59
|
+
end
|
46
60
|
end
|
47
61
|
|
48
62
|
def scoping
|
@@ -78,10 +92,16 @@ module Aliyun
|
|
78
92
|
|
79
93
|
def page(val)
|
80
94
|
@opts[:page] = val - 1 if val >= 1
|
95
|
+
singleton_class.send(:define_method, :total_count) do
|
96
|
+
@total_count ||= count
|
97
|
+
end
|
98
|
+
singleton_class.send(:define_method, :total_pages) do
|
99
|
+
(total_count.to_f / (@opts[:line] || 100)).ceil
|
100
|
+
end
|
81
101
|
self
|
82
102
|
end
|
83
103
|
|
84
|
-
def
|
104
|
+
def api(opts)
|
85
105
|
@opts.merge!(opts)
|
86
106
|
self
|
87
107
|
end
|
@@ -93,11 +113,49 @@ module Aliyun
|
|
93
113
|
end
|
94
114
|
|
95
115
|
def sql(*statement)
|
96
|
-
|
116
|
+
unless statement[0].is_a?(String)
|
117
|
+
raise ParseStatementInvalid, 'Only support string statement'
|
118
|
+
end
|
119
|
+
ql = sanitize_array(*statement)
|
97
120
|
@opts[:sql] = ql if ql.present?
|
98
121
|
self
|
99
122
|
end
|
100
123
|
|
124
|
+
def where(*statement)
|
125
|
+
if statement[0].is_a?(String)
|
126
|
+
ql = sanitize_array(*statement)
|
127
|
+
@opts[:where] = ql
|
128
|
+
else
|
129
|
+
ql = statement_ql(*statement)
|
130
|
+
@opts[:search] = ql
|
131
|
+
end
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
def select(*fields)
|
136
|
+
@opts[:select] = fields.join(', ')
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
def group(*fields)
|
141
|
+
@opts[:group] = fields.join(', ')
|
142
|
+
self
|
143
|
+
end
|
144
|
+
|
145
|
+
def order(*fields)
|
146
|
+
if fields[0].is_a?(Hash)
|
147
|
+
@opts[:order] = fields[0].map do |k, v|
|
148
|
+
unless %w[asc desc].include?(v.to_s)
|
149
|
+
raise ArgumentError, "Direction \"#{v}\" is invalid. Valid directions are: [:asc, :desc, :ASC, :DESC]"
|
150
|
+
end
|
151
|
+
"#{k} #{v}"
|
152
|
+
end.join(', ')
|
153
|
+
else
|
154
|
+
@opts[:order] = fields.join(', ')
|
155
|
+
end
|
156
|
+
self
|
157
|
+
end
|
158
|
+
|
101
159
|
def query(opts = {})
|
102
160
|
@opts[:query] = opts
|
103
161
|
self
|
@@ -105,26 +163,38 @@ module Aliyun
|
|
105
163
|
|
106
164
|
def count
|
107
165
|
query = @opts.dup
|
108
|
-
if query[:
|
109
|
-
|
110
|
-
|
111
|
-
|
166
|
+
if query[:select].blank?
|
167
|
+
@opts[:select] = 'COUNT(*) as count'
|
168
|
+
sql = to_sql
|
169
|
+
else
|
170
|
+
_sql = to_sql
|
171
|
+
sql = "SELECT COUNT(*) as count"
|
172
|
+
sql += " FROM(#{_sql})" if _sql.present?
|
112
173
|
end
|
113
|
-
|
114
|
-
res =
|
115
|
-
res
|
174
|
+
query[:query] = "#{query[:search] || '*'}|#{sql}"
|
175
|
+
res = execute(query)
|
176
|
+
res.dig(0, 'count').to_i
|
177
|
+
end
|
178
|
+
|
179
|
+
def sum(field)
|
180
|
+
@opts[:select] = "SUM(#{field}) as sum"
|
181
|
+
query = @opts.dup
|
182
|
+
query[:query] = "#{query[:search] || '*'}|#{to_sql}"
|
183
|
+
res = execute(query)
|
184
|
+
res.dig(0, 'sum').to_f
|
116
185
|
end
|
117
186
|
|
118
187
|
def result
|
119
188
|
query = @opts.dup
|
120
|
-
if query[:page]
|
121
|
-
query[:line] ||= 100
|
122
|
-
query[:offset] = query[:page] * query[:line]
|
123
|
-
end
|
124
189
|
query[:query] = query[:search] || '*'
|
125
|
-
|
126
|
-
|
127
|
-
|
190
|
+
sql = to_sql
|
191
|
+
if sql.present?
|
192
|
+
query[:query] += "|#{sql}"
|
193
|
+
@opts[:line] = nil
|
194
|
+
@opts[:offset] = nil
|
195
|
+
@opts[:page] = nil
|
196
|
+
end
|
197
|
+
execute(query)
|
128
198
|
end
|
129
199
|
|
130
200
|
def load
|
@@ -137,8 +207,38 @@ module Aliyun
|
|
137
207
|
end
|
138
208
|
end
|
139
209
|
|
210
|
+
def to_sql
|
211
|
+
return @opts[:sql] if @opts[:sql].present?
|
212
|
+
opts = @opts.dup
|
213
|
+
sql_query = []
|
214
|
+
sql_query << "WHERE #{opts[:where]}" if opts[:where].present?
|
215
|
+
sql_query << "GROUP BY #{opts[:group]}" if opts[:group].present?
|
216
|
+
sql_query << "ORDER BY #{opts[:order]}" if opts[:order].present?
|
217
|
+
if sql_query.present? || opts[:select].present?
|
218
|
+
sql_query.insert(0, "SELECT #{opts[:select] || '*'}")
|
219
|
+
sql_query.insert(1, 'FROM log') unless opts[:select]&.match?(/from\s+log/i)
|
220
|
+
if opts[:line] || opts[:page] || opts[:offset]
|
221
|
+
parse_page
|
222
|
+
sql_query << "LIMIT #{@opts[:offset]},#{@opts[:line]}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
"#{opts[:query]}#{sql_query.join(' ')}"
|
226
|
+
end
|
227
|
+
|
140
228
|
private
|
141
229
|
|
230
|
+
def execute(query)
|
231
|
+
puts query.slice(:from, :to, :search, :query).to_json
|
232
|
+
res = Log.record_connection.get_logs(@klass.project_name, @klass.logstore_name, query)
|
233
|
+
JSON.parse(res)
|
234
|
+
end
|
235
|
+
|
236
|
+
def parse_page
|
237
|
+
@opts[:line] ||= 100
|
238
|
+
@opts[:page] ||= 0
|
239
|
+
@opts[:offset] = @opts[:page] * @opts[:line]
|
240
|
+
end
|
241
|
+
|
142
242
|
def statement_ql(*statement)
|
143
243
|
if statement.size == 1
|
144
244
|
sanitize_hash(statement.first)
|
@@ -150,12 +250,28 @@ module Aliyun
|
|
150
250
|
def sanitize_hash(search_content)
|
151
251
|
return search_content unless search_content.is_a?(Hash)
|
152
252
|
|
153
|
-
search_content.
|
154
|
-
|
253
|
+
search_content.reject { |_, v| v.nil? }.map do |key, value|
|
254
|
+
options = @klass.attributes[:"#{key}"]
|
255
|
+
unless options
|
155
256
|
raise UnknownAttributeError, "unknown field '#{key}' for #{@klass.name}."
|
156
257
|
end
|
157
258
|
|
158
|
-
|
259
|
+
raise_if_hash_quote(value)
|
260
|
+
|
261
|
+
cast_type = options[:cast_type]
|
262
|
+
|
263
|
+
is_tag = @klass.tag_attributes[:"#{key}"]
|
264
|
+
key = :"__tag__:#{key}" if is_tag
|
265
|
+
if value.is_a?(Array)
|
266
|
+
values = value.uniq.map { |v| is_tag ? v : _quote(cast_type, v) }
|
267
|
+
str_values = values.map { |v| "#{key}: #{v}" }.join(' OR ')
|
268
|
+
values.size > 1 ? "(#{str_values})" : str_values
|
269
|
+
elsif value.is_a?(Range)
|
270
|
+
"#{key} in [#{value.begin} #{value.end}]"
|
271
|
+
else
|
272
|
+
quote_value = is_tag ? value : _quote(cast_type, value)
|
273
|
+
"#{key}: #{quote_value}"
|
274
|
+
end
|
159
275
|
end.join(' AND ')
|
160
276
|
end
|
161
277
|
|
@@ -165,7 +281,7 @@ module Aliyun
|
|
165
281
|
replace_named_bind_variables(statement, values.first)
|
166
282
|
elsif statement.include?('?')
|
167
283
|
replace_bind_variables(statement, values)
|
168
|
-
elsif statement.blank?
|
284
|
+
elsif statement.blank? || values.blank?
|
169
285
|
statement
|
170
286
|
else
|
171
287
|
statement % values.collect(&:to_s)
|
@@ -175,7 +291,14 @@ module Aliyun
|
|
175
291
|
def replace_named_bind_variables(statement, bind_vars)
|
176
292
|
statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
|
177
293
|
if bind_vars.include?(match = Regexp.last_match(2).to_sym)
|
178
|
-
|
294
|
+
match_value = bind_vars[match]
|
295
|
+
raise_if_hash_quote(match_value)
|
296
|
+
if match_value.is_a?(Array) || match_value.is_a?(Range)
|
297
|
+
values = match_value.map { |v| _quote_type_value(v) }
|
298
|
+
values.join(', ')
|
299
|
+
else
|
300
|
+
_quote_type_value(match_value)
|
301
|
+
end
|
179
302
|
else
|
180
303
|
raise ParseStatementInvalid, "missing value for :#{match} in #{statement}"
|
181
304
|
end
|
@@ -191,7 +314,42 @@ module Aliyun
|
|
191
314
|
end
|
192
315
|
bound = values.dup
|
193
316
|
statement.gsub(/\?/) do
|
194
|
-
|
317
|
+
value = bound.shift
|
318
|
+
raise_if_hash_quote(value)
|
319
|
+
if value.is_a?(Array) || value.is_a?(Range)
|
320
|
+
values = value.map { |v| _quote_type_value(v) }
|
321
|
+
values.join(', ')
|
322
|
+
else
|
323
|
+
_quote_type_value(value)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def _quote(type, value)
|
329
|
+
v = TypeCasting.cast_field(value, cast_type: type || :string)
|
330
|
+
case type
|
331
|
+
when :string, nil then "'#{v.to_s}'"
|
332
|
+
when :bigdecimal then v.to_s("F")
|
333
|
+
when :integer then v.to_s.to_i
|
334
|
+
when :datetime, :date then "'#{v.iso8601}'"
|
335
|
+
else
|
336
|
+
value.to_s
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def _quote_type_value(value)
|
341
|
+
case value.class.name
|
342
|
+
when 'String' then "'#{value.to_s}'"
|
343
|
+
when 'BigDecimal', 'Float' then value.to_s("F")
|
344
|
+
when 'Date', 'DateTime', 'Time' then "'#{value.iso8601}'"
|
345
|
+
else
|
346
|
+
value
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def raise_if_hash_quote(value)
|
351
|
+
if value.is_a?(Hash) || value.is_a?(ActiveSupport::HashWithIndifferentAccess)
|
352
|
+
raise ParseStatementInvalid, "can't quote Hash"
|
195
353
|
end
|
196
354
|
end
|
197
355
|
|
@@ -10,9 +10,10 @@ module Aliyun
|
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
delegate :load, :result, :count, to: :all
|
14
|
-
delegate :where, :query, :search, :sql, :from, :to,
|
15
|
-
:page, :line, :limit, :offset,
|
13
|
+
delegate :load, :result, :count, :sum, to: :all
|
14
|
+
delegate :where, :query, :search, :sql, :from, :to, :api,
|
15
|
+
:page, :line, :limit, :offset, :select, :group,
|
16
|
+
:order, :to_sql, to: :all
|
16
17
|
delegate :first, :last, :second, :third, :fourth, :fifth, :find_offset, to: :all
|
17
18
|
|
18
19
|
def current_scope
|
@@ -9,7 +9,7 @@ module Aliyun
|
|
9
9
|
TYPE_MAPPING = {
|
10
10
|
text: :string,
|
11
11
|
long: :integer,
|
12
|
-
double: :
|
12
|
+
double: :float,
|
13
13
|
json: :json
|
14
14
|
}.freeze
|
15
15
|
|
@@ -55,7 +55,17 @@ module Aliyun
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
class StringType < Value
|
58
|
+
class StringType < Value
|
59
|
+
def cast(value)
|
60
|
+
if value.nil?
|
61
|
+
''
|
62
|
+
elsif value.is_a? String
|
63
|
+
value.dup
|
64
|
+
else
|
65
|
+
value.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
59
69
|
|
60
70
|
class DateType < Value
|
61
71
|
def cast(value)
|
@@ -66,7 +76,7 @@ module Aliyun
|
|
66
76
|
|
67
77
|
def dump(value)
|
68
78
|
if value.respond_to?(:to_date)
|
69
|
-
value.
|
79
|
+
value.to_date.to_s
|
70
80
|
else
|
71
81
|
value.to_s
|
72
82
|
end
|
@@ -148,6 +158,26 @@ module Aliyun
|
|
148
158
|
end
|
149
159
|
end
|
150
160
|
|
161
|
+
class FloatType < Value
|
162
|
+
def cast(value)
|
163
|
+
if value == true
|
164
|
+
1
|
165
|
+
elsif value == false
|
166
|
+
0
|
167
|
+
elsif value.is_a?(Symbol)
|
168
|
+
value.to_s.to_f
|
169
|
+
elsif value.is_a?(String) && value.blank?
|
170
|
+
nil
|
171
|
+
elsif value.is_a?(Float) && !value.finite?
|
172
|
+
nil
|
173
|
+
elsif !value.respond_to?(:to_f)
|
174
|
+
nil
|
175
|
+
else
|
176
|
+
value.to_f
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
151
181
|
class JsonType < Value
|
152
182
|
def cast(value)
|
153
183
|
return value unless value.is_a?(String)
|
@@ -183,6 +213,7 @@ module Aliyun
|
|
183
213
|
register(:datetime, DateTimeType)
|
184
214
|
register(:bigdecimal, BigDecimalType)
|
185
215
|
register(:integer, IntegerType)
|
216
|
+
register(:float, FloatType)
|
186
217
|
register(:json, JsonType)
|
187
218
|
end
|
188
219
|
end
|
data/lib/aliyun/log/request.rb
CHANGED
@@ -7,6 +7,8 @@ require 'digest'
|
|
7
7
|
require 'date'
|
8
8
|
require 'zlib'
|
9
9
|
|
10
|
+
require_relative 'utils'
|
11
|
+
|
10
12
|
module Aliyun
|
11
13
|
module Log
|
12
14
|
class Request
|
@@ -16,25 +18,6 @@ module Aliyun
|
|
16
18
|
@config = config
|
17
19
|
end
|
18
20
|
|
19
|
-
def get_resource_path(resources = {})
|
20
|
-
resources ||= {}
|
21
|
-
res = '/'
|
22
|
-
if resources[:logstore]
|
23
|
-
res = "#{res}logstores"
|
24
|
-
res = "#{res}/#{resources[:logstore]}" unless resources[:logstore].empty?
|
25
|
-
end
|
26
|
-
res = "#{res}/#{resources[:action]}" if resources[:action]
|
27
|
-
res
|
28
|
-
end
|
29
|
-
|
30
|
-
def get_request_url(resources = {})
|
31
|
-
resources ||= {}
|
32
|
-
url = URI.parse(@config.endpoint)
|
33
|
-
url.host = "#{resources[:project]}." + url.host if resources[:project]
|
34
|
-
url.path = get_resource_path(resources)
|
35
|
-
url.to_s
|
36
|
-
end
|
37
|
-
|
38
21
|
def get(resources, payload = {})
|
39
22
|
do_request('GET', resources, payload)
|
40
23
|
end
|
@@ -52,10 +35,11 @@ module Aliyun
|
|
52
35
|
end
|
53
36
|
|
54
37
|
def do_request(verb, resources, payload)
|
55
|
-
resource_path = get_resource_path(resources)
|
38
|
+
resource_path = Utils.get_resource_path(resources)
|
39
|
+
url = Utils.get_request_url(@config.endpoint, resources)
|
56
40
|
request_options = {
|
57
41
|
method: verb,
|
58
|
-
url:
|
42
|
+
url: url,
|
59
43
|
open_timeout: @config.open_timeout,
|
60
44
|
read_timeout: @config.read_timeout
|
61
45
|
}
|
@@ -75,15 +59,17 @@ module Aliyun
|
|
75
59
|
response = request.execute do |resp|
|
76
60
|
if resp.code >= 300
|
77
61
|
e = ServerError.new(resp)
|
78
|
-
logger.error(e.to_s)
|
62
|
+
logger.error("#{e.to_s} #{resp.code} #{resp}")
|
79
63
|
raise e
|
80
64
|
else
|
81
65
|
resp.return!
|
82
66
|
end
|
83
67
|
end
|
84
68
|
|
85
|
-
logger.debug("Received HTTP response, code: #{response.code},
|
86
|
-
"#{
|
69
|
+
logger.debug("Received HTTP response, code: #{response.code}, " \
|
70
|
+
"url: #{request_options[:url]}, " \
|
71
|
+
"method: #{verb}, headers: #{response.headers}, " \
|
72
|
+
"body: #{response.body.force_encoding('UTF-8')}")
|
87
73
|
|
88
74
|
response
|
89
75
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
|
5
|
+
module Aliyun
|
6
|
+
module Log
|
7
|
+
module Utils
|
8
|
+
module_function
|
9
|
+
def get_resource_path(resources = {})
|
10
|
+
resources ||= {}
|
11
|
+
res = '/'
|
12
|
+
if resources[:logstore]
|
13
|
+
res = "#{res}logstores"
|
14
|
+
res = "#{res}/#{resources[:logstore]}" unless resources[:logstore].empty?
|
15
|
+
end
|
16
|
+
res = "#{res}/#{resources[:action]}" if resources[:action]
|
17
|
+
res
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_request_url(endpoint, resources = {})
|
21
|
+
resources ||= {}
|
22
|
+
url = URI.parse(endpoint)
|
23
|
+
url.host = "#{resources[:project]}." + url.host if resources[:project]
|
24
|
+
url.path = get_resource_path(resources)
|
25
|
+
url.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/aliyun/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aliyun-log
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
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-
|
11
|
+
date: 2020-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -114,6 +114,20 @@ dependencies:
|
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '3.0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: webmock
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '3.0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '3.0'
|
117
131
|
description: Aliyun Log SDK for Ruby 阿里云日志服务(SLS) Ruby SDK, 目前仅实现基于Restfull部分接口和简单Model映射
|
118
132
|
email:
|
119
133
|
- yingce@live.com
|
@@ -141,6 +155,7 @@ files:
|
|
141
155
|
- lib/aliyun/log/record/type_casting.rb
|
142
156
|
- lib/aliyun/log/request.rb
|
143
157
|
- lib/aliyun/log/server_error.rb
|
158
|
+
- lib/aliyun/log/utils.rb
|
144
159
|
- lib/aliyun/version.rb
|
145
160
|
homepage: https://github.com/yingce/aliyun-log
|
146
161
|
licenses:
|