Class: AliyunSls::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/aliyun_sls/connection.rb

Instance Method Summary collapse

Constructor Details

#initialize(project, region, access_key_secret, aliyun_access_key, opts = {}) ⇒ Connection

深圳:cn-shenzhen.sls.aliyuncs.com



35
36
37
38
39
40
41
42
43
44
# File 'lib/aliyun_sls/connection.rb', line 35

def initialize(project, region, access_key_secret, aliyun_access_key, opts={})
    default_headers = {
        "x-sls-apiversion" => "0.4.0",
        "x-sls-signaturemethod" => "hmac-sha1"
    }
    @headers = default_headers.update opts
    @aliyun_access_key = aliyun_access_key
    @access_key_secret = access_key_secret
    @host = "#{project}.#{region}"
end

Instance Method Details

#canonicalized_resource(logstorename, query = {}) ⇒ Object

“CanonicalizedResource”的构造方式如下:

  1. 将CanonicalizedResource设置为空字符串(“”);

  2. 放入要访问的SLS资源:“/logstores/logstorename”(无logstorename则不填);

  3. 如请求包含查询字符串(QUERY_STRING),则在CanonicalizedResource字符串尾部添加“?”和查询字符串。



98
99
100
101
102
103
104
# File 'lib/aliyun_sls/connection.rb', line 98

def canonicalized_resource(logstorename, query={})
    u = logstorename ? URI.parse("/logstores/#{logstorename}") : URI.parse("/logstores")
    if query.size != 0
        u.query = query.inject([]){|s, a| s << "#{a[0]}=#{a[1]}"}.join('&')
    end
    u.to_s
end

#canonicalized_sls_headers(headers) ⇒ Object

“CanonicalizedSLSHeaders”的构造方式如下:

  1. 将所有以“x-sls-”为前缀的HTTP请求头的名字转换成小写字母;

  2. 将上一步得到的所有SLS自定义请求头按照字典序进行升序排序;

  3. 删除请求头和内容之间分隔符两端出现的任何空格;

  4. 将所有的头和内容用n分隔符组合成最后的CanonicalizedSLSHeader;



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/aliyun_sls/connection.rb', line 81

def canonicalized_sls_headers(headers)
    h = {}
    headers.each { |k, v|  
        if k =~ /x-sls-.*/
            h[k.downcase] = v
        end
    }
    h.keys.sort.map { |e|  
        h[e]
        "#{e}:#{h[e].gsub(/^\s+/,'')}"
    }.join($/)
end

#compact_headers(content, compressed) ⇒ Object

content是LogGroup



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/aliyun_sls/connection.rb', line 117

def compact_headers(content, compressed)
    headers = @headers.dup
    # headers["x-sls-date"] = 
    headers["Date"] = DateTime.now.httpdate
    headers["x-sls-bodyrawsize"] = "0"

    if content and compressed
        body = content.encode.to_s
        headers["Content-Length"] = compressed.bytesize.to_s
        # 日志内容包含的日志必须小于3MB和4096条。
        raise AliyunSls::PostBodyTooLarge, "content length is larger than 3MB" if headers["Content-Length"].to_i > 3*1024**2*8
        raise AliyunSls::PostBodyTooLarge, "content size is more than 4096" if content.logs.size > 4096
        # MD5必须为大写字符串
        headers["Content-MD5"] = Digest::MD5.hexdigest(compressed).upcase
        headers["Content-Type"] = "application/x-protobuf"
        headers["x-sls-bodyrawsize"] = body.bytesize.to_s
        headers["x-sls-compresstype"] = "deflate"
    end
    headers
end

#list_logstoresObject



149
150
151
152
153
154
155
156
157
# File 'lib/aliyun_sls/connection.rb', line 149

def list_logstores
    headers = compact_headers(nil, nil)
    headers["Authorization"] = signature("GET", nil, headers, nil, {})

    u = URI.parse("http://#{@host}/logstores")
    headers["Referer"] = u.to_s
    rsp = RestClient.get u.to_s, headers
    parse_response(rsp)
end

#parse_response(rsp) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
# File 'lib/aliyun_sls/connection.rb', line 159

def parse_response(rsp)
    # 如果返回结果报错,则解析报错内容打印到日志中
    if rsp.code.to_s =~ /[4|5]\d\d/
        msg = "status #{rsp.code} body #{rsp}"
        if $logger and $logger.respond_to?(:error)
            $logger.error msg
        else
            puts msg
        end
    end
end

#puts_logs(logstorename, content) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'lib/aliyun_sls/connection.rb', line 138

def puts_logs(logstorename, content)
    # 压缩content数据
    compressed = Zlib::Deflate.deflate(content.encode.to_s)
    headers = compact_headers(content, compressed)
    headers["Authorization"] = signature("POST", logstorename, headers, content, {})

    u = URI.parse("http://#{@host}/logstores/#{logstorename}")
    rsp = RestClient.post u.to_s, compressed, headers
    parse_response(rsp)
end

#sign(verb, logstorename, headers, content, query) ⇒ Object

目前,SLS API只支持一种数字签名算法,即默认签名算法“hmac-sha1”。其整个签名公式如下: Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret))



108
109
110
# File 'lib/aliyun_sls/connection.rb', line 108

def sign(verb, logstorename, headers, content, query)
    Base64.encode64((HMAC::SHA1.new(@access_key_secret) << string_to_sign(verb, logstorename, headers, content, query).chomp).digest).strip
end

#signature(verb, logstorename, headers, content, query) ⇒ Object



112
113
114
# File 'lib/aliyun_sls/connection.rb', line 112

def signature(verb, logstorename, headers, content, query)
    "SLS #{@aliyun_access_key}:#{sign(verb, logstorename, headers, content, query)}"
end

#string_to_sign(verb, logstorename, headers, content, query = {}) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/aliyun_sls/connection.rb', line 46

def string_to_sign(verb, logstorename, headers, content, query={})
    if content
        string_to_sign_with_content(verb, logstorename, headers, query)
    else
        string_to_sign_without_content(verb, logstorename, headers, query)
    end
end

#string_to_sign_with_content(verb, logstorename, headers, query = {}) ⇒ Object



54
55
56
57
58
59
60
61
62
63
# File 'lib/aliyun_sls/connection.rb', line 54

def string_to_sign_with_content(verb, logstorename, headers, query={})
    <<-DOC
#{verb}
#{headers['Content-MD5']}
#{headers['Content-Type']}
#{headers['Date']}
#{canonicalized_sls_headers(headers)}
#{canonicalized_resource(logstorename, query)}
DOC
end

#string_to_sign_without_content(verb, logstorename, headers, query = {}) ⇒ Object



65
66
67
68
69
70
71
72
73
74
# File 'lib/aliyun_sls/connection.rb', line 65

def string_to_sign_without_content(verb, logstorename, headers, query={})
    <<-DOC
#{verb}


#{headers['Date']}
#{canonicalized_sls_headers(headers)}
#{canonicalized_resource(logstorename, query)}
DOC
end