grpc_access_logging_interceptor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9a68e9f69eb2185dd62fa4a09fce523451b64b51e1bc235ab10412ebe2ee1e8f
4
+ data.tar.gz: 8940b1bd83aea87e84b43c9a7bbd82246529cfcefbc291bb93b4dffc0ae007ea
5
+ SHA512:
6
+ metadata.gz: 2ab3910b015437b573ccfde6adc105b303286435eefad110246327469abcbd2c36ec9880ca37af7fbddbd9f244d026db086d1ab39a554a0b52c7ab4807148b96
7
+ data.tar.gz: 365573f561f728423a95f13656c5d5a392f000e68ede2b460819a03093506c3f4e0f75fe8d00c3a04ab2a442c910b4eb79841c234aa0d7f7bbeeceb117fe0d40
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.2
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in grpc_access_logging_interceptor.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ grpc_access_logging_interceptor (0.0.1)
5
+ grpc
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ coderay (1.1.2)
11
+ diff-lcs (1.3)
12
+ google-protobuf (3.10.0-universal-darwin)
13
+ googleapis-common-protos-types (1.0.4)
14
+ google-protobuf (~> 3.0)
15
+ grpc (1.24.0)
16
+ google-protobuf (~> 3.8)
17
+ googleapis-common-protos-types (~> 1.0)
18
+ method_source (0.9.2)
19
+ pry (0.12.2)
20
+ coderay (~> 1.1.0)
21
+ method_source (~> 0.9.0)
22
+ pry-doc (1.0.0)
23
+ pry (~> 0.11)
24
+ yard (~> 0.9.11)
25
+ rake (10.5.0)
26
+ rspec (3.9.0)
27
+ rspec-core (~> 3.9.0)
28
+ rspec-expectations (~> 3.9.0)
29
+ rspec-mocks (~> 3.9.0)
30
+ rspec-core (3.9.0)
31
+ rspec-support (~> 3.9.0)
32
+ rspec-expectations (3.9.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.9.0)
35
+ rspec-mocks (3.9.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.9.0)
38
+ rspec-support (3.9.0)
39
+ timecop (0.9.1)
40
+ yard (0.9.20)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ bundler (~> 2.0)
47
+ google-protobuf
48
+ grpc_access_logging_interceptor!
49
+ pry
50
+ pry-doc
51
+ rake (~> 10.0)
52
+ rspec
53
+ timecop
54
+
55
+ BUNDLED WITH
56
+ 2.0.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Nao Minami
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # GrpcAccessLoggingInterceptor
2
+ An interceptor for access logging with gRPC.
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'grpc_access_logging_interceptor'
10
+ ```
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install grpc_access_logging_interceptor
19
+
20
+ ## Usage
21
+ Please set a `GrpcAccessLoggingInterceptor` as an interceptor of your gRPC application.
22
+
23
+ ```ruby
24
+ require 'grpc'
25
+ require 'grpc_access_logging_interceptor'
26
+
27
+ server = GRPC::RpcServer.new(
28
+ interceptors: [
29
+ GrpcAccessLoggingInterceptor.new,
30
+ ]
31
+ )
32
+ server.handle(MyHandler.new)
33
+ server.run_till_terminated_or_interrupted(['SIGINT'])
34
+ ```
35
+
36
+ With this setting, the following access logs will be printed.
37
+
38
+ ```console
39
+ I, [2019-03-15T00:00:00.000000 #30034] INFO -- : {"remote_addr":"127.0.0.1","accessed_at":"2019-03-15 00:00:00.000000","params":"{\"value\":\"World\"}","user_agent":"grpc-node/1.19.0 grpc-c/7.0.0 (linux; chttp2; gold)","grpc_method":"/test.Test/HelloRpc","grpc_metadata":"{\"user-agent\":\"grpc-node/1.19.0 grpc-c/7.0.0 (linux; chttp2; gold)\"}","grpc_status_code":0,"response_time_ms":0.0}
40
+ ```
41
+
42
+ ### The information in the access log
43
+
44
+ You can get information for the following fields.
45
+
46
+ | Field Name | Meaning |
47
+ | -- | -- |
48
+ | accessed_at | The time that the request was received |
49
+ | grpc_metadata | [gRPC's metadata](https://grpc.io/docs/guides/concepts/#metadata) |
50
+ | grpc_method | A path string (cf. [gRPC over HTTP2](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)) |
51
+ | grpc_status_code | [Status codes in gRPC](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md) |
52
+ | params | Request parameter in JSON |
53
+ | remote_addr | IP address of a client (e.g. `"127.0.0.1"`) |
54
+ | response_time_ms | Response time (ms) |
55
+ | user_agent | User agent (e.g. `"grpc_health_probe grpc-go/1.17.0"`) |
56
+
57
+ ### Custom Logger
58
+
59
+ You can use your custom logger.
60
+
61
+ ```ruby
62
+ server = GRPC::RpcServer.new(
63
+ interceptors: [
64
+ GrpcAccessLoggingInterceptor.new(logger: YourCustomLogger.new),
65
+ ]
66
+ )
67
+ ```
68
+
69
+ ## Development
70
+
71
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
72
+
73
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
74
+
75
+ ## Contributing
76
+
77
+ Bug reports and pull requests are welcome on GitHub at https://github.com/south37/grpc_access_logging_interceptor.
78
+
79
+ ## License
80
+
81
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "grpc_access_logging_interceptor"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,36 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "grpc_access_logging_interceptor/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "grpc_access_logging_interceptor"
7
+ spec.version = GrpcAccessLoggingInterceptor::VERSION
8
+ spec.authors = ["Nao Minami"]
9
+ spec.email = ["south37777@gmail.com"]
10
+
11
+ spec.summary = %q{An interceptor for access logging with gRPC.}
12
+ spec.description = %q{An interceptor for access logging with gRPC.}
13
+ spec.homepage = "https://github.com/south37/grpc_access_logging_interceptor"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/south37/grpc_access_logging_interceptor"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_development_dependency "bundler", "~> 2.0"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "pry-doc"
33
+ spec.add_development_dependency "google-protobuf"
34
+ spec.add_development_dependency "timecop"
35
+ spec.add_dependency "grpc"
36
+ end
@@ -0,0 +1,10 @@
1
+ require "grpc_access_logging_interceptor/version"
2
+ require "grpc_access_logging_interceptor/server_interceptor"
3
+
4
+ module GrpcAccessLoggingInterceptor
5
+ class << self
6
+ def new(options = {})
7
+ ServerInterceptor.new(**options)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ require "json"
2
+ require "logger"
3
+
4
+ module GrpcAccessLoggingInterceptor
5
+ class DefaultLogger
6
+ # @param [#info] logger
7
+ def initialize(logger: Logger.new($stdout))
8
+ @logger = logger
9
+ end
10
+
11
+ # @param [Hash] hash
12
+ def log(data)
13
+ @logger.info(data.to_json)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,122 @@
1
+ require "grpc"
2
+ require "grpc_access_logging_interceptor/default_logger"
3
+
4
+ module GrpcAccessLoggingInterceptor
5
+ class ServerInterceptor < GRPC::ServerInterceptor
6
+ USER_AGENT_KEY = "user-agent"
7
+
8
+ # @param [#log] logger
9
+ # @param [#filter, nil] params_filter
10
+ # @param [#call, nil] custom_data_provider
11
+ def initialize(logger: DefaultLogger.new, params_filter: nil, custom_data_provider: nil)
12
+ @logger = logger
13
+ @params_filter = params_filter
14
+ @custom_data_provider = custom_data_provider
15
+ end
16
+
17
+ ##
18
+ # Intercept a unary request response call.
19
+ #
20
+ # @param [Object] request
21
+ # @param [GRPC::ActiveCall::SingleReqView] call
22
+ # @param [Method] method
23
+ #
24
+ def request_response(request:, call:, method:)
25
+ accessed_at = Time.now
26
+
27
+ data = {
28
+ remote_addr: remote_addr(call.peer),
29
+ accessed_at: accessed_at.utc.strftime('%Y-%m-%d %H:%M:%S.%6N'),
30
+ params: filter(request.to_h).to_json,
31
+ user_agent: call.metadata[USER_AGENT_KEY],
32
+ grpc_method: grpc_method(method),
33
+ grpc_metadata: call.metadata.to_json,
34
+ }
35
+ data.merge!(custom_data(request: request, call: call, method: method))
36
+
37
+ yield
38
+
39
+ data[:grpc_status_code] = 0 # OK
40
+ rescue StandardError => e
41
+ data[:grpc_status_code] = grpc_status_code(e)
42
+ raise e
43
+ ensure
44
+ data[:response_time_ms] = response_time_ms(accessed_at)
45
+ log(data)
46
+ end
47
+
48
+ # NOTE: For now, we don't support server_streamer, client_streamer and bidi_streamer
49
+
50
+ private
51
+
52
+ # @param [Object] peer
53
+ # @return [String, nil]
54
+ def remote_addr(peer)
55
+ # Usually peer is a string such as "ipv4:127.0.0.1:63634"
56
+ if peer.is_a?(String) && peer[0..4] == 'ipv4:'
57
+ peer.split(':')[1]
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ # @param [Method] method
64
+ # @return [String]
65
+ def grpc_method(method)
66
+ # We use path, which is represented as "/" Service-Name "/" {method name}
67
+ # e.g. /google.pubsub.v2.PublisherService/CreateTopic.
68
+ # cf. https://github.com/grpc/grpc/blob/v1.24.0/doc/PROTOCOL-HTTP2.md
69
+ "/#{method.owner.service_name}/#{camelize(method.name.to_s)}"
70
+ end
71
+
72
+ # @param [String] term
73
+ # @return [String]
74
+ def camelize(term)
75
+ term.split("_").map(&:capitalize).join
76
+ end
77
+
78
+ # @param [Hash] params
79
+ # @return [Hash]
80
+ def filter(params)
81
+ if @params_filter
82
+ @params_filter.filter(params)
83
+ else
84
+ params
85
+ end
86
+ end
87
+
88
+ # @param [Object] request
89
+ # @param [GRPC::ActiveCall::SingleReqView] call
90
+ # @param [Method] method
91
+ # @return [Hash]
92
+ def custom_data(request:, call:, method:)
93
+ if @custom_data_provider
94
+ @custom_data_provider.call(request, call, method)
95
+ else
96
+ {}
97
+ end
98
+ end
99
+
100
+ # @param [StandardError] e
101
+ # @return [Integer] represents the grpc status code
102
+ def grpc_status_code(e)
103
+ case e
104
+ when GRPC::BadStatus
105
+ e.code
106
+ else
107
+ 2 # GRPC::Unknown
108
+ end
109
+ end
110
+
111
+ # @param [Time] from
112
+ # @return [Integer]
113
+ def response_time_ms(from)
114
+ (Time.now - from) * 1000
115
+ end
116
+
117
+ # @param [Hash] data
118
+ def log(data)
119
+ @logger.log(data)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,3 @@
1
+ module GrpcAccessLoggingInterceptor
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grpc_access_logging_interceptor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nao Minami
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-doc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: google-protobuf
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: grpc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: An interceptor for access logging with gRPC.
126
+ email:
127
+ - south37777@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".travis.yml"
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - bin/console
141
+ - bin/setup
142
+ - grpc_access_logging_interceptor.gemspec
143
+ - lib/grpc_access_logging_interceptor.rb
144
+ - lib/grpc_access_logging_interceptor/default_logger.rb
145
+ - lib/grpc_access_logging_interceptor/server_interceptor.rb
146
+ - lib/grpc_access_logging_interceptor/version.rb
147
+ homepage: https://github.com/south37/grpc_access_logging_interceptor
148
+ licenses:
149
+ - MIT
150
+ metadata:
151
+ homepage_uri: https://github.com/south37/grpc_access_logging_interceptor
152
+ source_code_uri: https://github.com/south37/grpc_access_logging_interceptor
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.0.3
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: An interceptor for access logging with gRPC.
172
+ test_files: []