appengine 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f0431694401f2a56557604bd8db4c89bc8b3732
4
- data.tar.gz: 9e7484adb81a05b7d4b2959c28e5bca82439fcb3
3
+ metadata.gz: c5603a0560a10f3f6d0c6a6cd9a35ad8dcec9965
4
+ data.tar.gz: 92d67d00bfb992d723ccb5628f4f3f53c75e1a48
5
5
  SHA512:
6
- metadata.gz: b3e2ab45cb9771049c9862b92c98f70802ea0c032dbef90db899ba0b24b89903bea926bafe2587773fb5e2816aec5e60dd0a3782fd3993475b6d5d4ea37c5a24
7
- data.tar.gz: 2b71c96b247e02a45b606193cc2aa001aafc532f1e4a5c28e3bf3e7c2917a2abd62a69e63a6bc5ab8d01ff420a2b82ab9d2f920a75b64228610bfe212b9d0c3b
6
+ metadata.gz: 381abeeea878aa676f40fbd444c022f2639f05d175c6457efd02e26c0eaa54ade5b1e032ac2dd553aa067afc594cb790be2828c230122d121a9d221dcc239657
7
+ data.tar.gz: 880a1741725629a5588795d1d7f38bbd340cd3a814a93e597bacdfa595080d191ecc25e1313aa2fd8e931406fb74415227ca561d3794c7bca6d0a8fbfb79433f
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ This is the change history for the appengine gem.
4
+
5
+ ## v0.2.0 (2016-05-04)
6
+
7
+ * Tools for integration with the Google Cloud Console logger, including
8
+ Rack middleware and a Railtie.
9
+
10
+ ## v0.1.0 (2016-04-07)
11
+
12
+ * Initial release, reserving the appengine name. No functionality.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,27 @@
1
+ Want to contribute? Great! First, read this page (including the small print at the end).
2
+
3
+ ### Before you contribute
4
+ Before we can use your code, you must sign the
5
+ [Google Individual Contributor License Agreement]
6
+ (https://cla.developers.google.com/about/google-individual)
7
+ (CLA), which you can do online. The CLA is necessary mainly because you own the
8
+ copyright to your changes, even after your contribution becomes part of our
9
+ codebase, so we need your permission to use and distribute your code. We also
10
+ need to be sure of various other things—for instance that you'll tell us if you
11
+ know that your code infringes on other people's patents. You don't have to sign
12
+ the CLA until after you've submitted your code for review and a member has
13
+ approved it, but you must do it before we can put your code into our codebase.
14
+ Before you start working on a larger contribution, you should get in touch with
15
+ us first through the issue tracker with your idea so that we can help out and
16
+ possibly guide you. Coordinating up front makes it much easier to avoid
17
+ frustration later on.
18
+
19
+ ### Code reviews
20
+ All submissions, including submissions by project members, require review. We
21
+ use Github pull requests for this purpose.
22
+
23
+ ### The small print
24
+ Contributions made by corporations are covered by a different agreement than
25
+ the one above, the
26
+ [Software Grant and Corporate Contributor License Agreement]
27
+ (https://cla.developers.google.com/about/google-corporate).
data/LICENSE CHANGED
@@ -1,5 +1,4 @@
1
-
2
- Apache License
1
+ Apache License
3
2
  Version 2.0, January 2004
4
3
  http://www.apache.org/licenses/
5
4
 
@@ -179,7 +178,7 @@
179
178
  APPENDIX: How to apply the Apache License to your work.
180
179
 
181
180
  To apply the Apache License to your work, attach the following
182
- boilerplate notice, with the fields enclosed by brackets "[]"
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
183
182
  replaced with your own identifying information. (Don't include
184
183
  the brackets!) The text should be enclosed in the appropriate
185
184
  comment syntax for the file format. We also recommend that a
@@ -187,7 +186,7 @@
187
186
  same "printed page" as the copyright notice for easier
188
187
  identification within third-party archives.
189
188
 
190
- Copyright 2016 Google Inc.
189
+ Copyright {yyyy} {name of copyright owner}
191
190
 
192
191
  Licensed under the Apache License, Version 2.0 (the "License");
193
192
  you may not use this file except in compliance with the License.
@@ -199,4 +198,4 @@
199
198
  distributed under the License is distributed on an "AS IS" BASIS,
200
199
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
200
  See the License for the specific language governing permissions and
202
- limitations under the License.
201
+ limitations under the License.
data/README.md CHANGED
@@ -1,41 +1,67 @@
1
- # Appengine
1
+ Google App Engine Integration Tools
2
+ ===================================
2
3
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/appengine`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+ This repository contains the "appengine" gem, a collection of libraries and
5
+ plugins for integrating Ruby apps with Google App Engine. It is not required
6
+ for deploying a ruby application to Google App Engine, but it provides a
7
+ number of convenience hooks for better integrating into the App Engine
8
+ environment.
4
9
 
5
- TODO: Delete this and the text above, and describe your gem
10
+ Currently, it includes:
6
11
 
7
- ## Installation
8
-
9
- Add this line to your application's Gemfile:
12
+ * A way to configure the Logger to log to the Google Cloud Console.
10
13
 
11
- ```ruby
12
- gem 'appengine'
13
- ```
14
+ For more information on using Google Cloud Platform to deploy Ruby apps,
15
+ please visit http://cloud.google.com/ruby
14
16
 
15
- And then execute:
17
+ ## Installation
16
18
 
17
- $ bundle
19
+ To install, include the "appengine" gem in your Gemfile. e.g.
18
20
 
19
- Or install it yourself as:
21
+ gem "appengine"
20
22
 
21
- $ gem install appengine
23
+ If you are running [Ruby On Rails](http://rubyonrails.org/) 4.0 or later, this
24
+ gem will automatically install a Railtie that provides its capabilities. You
25
+ may need to include the line:
22
26
 
23
- ## Usage
27
+ require "appengine"
24
28
 
25
- TODO: Write usage instructions here
29
+ in your `config/application.rb` file if you aren't already requiring all
30
+ bundled gems. You may provide additional configuration via the
31
+ `config.appengine` object. See below for more details.
26
32
 
27
- ## Development
33
+ If you are using a different Rack-based framework such as
34
+ [Sinatra](http://sinatrarb.com/), you can use the provided middlewares. See
35
+ the more detailed instructions below.
28
36
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
37
+ ## Google Cloud Console logger integration
30
38
 
31
- 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).
39
+ In order for your application logs to appear in the Google Cloud Console with
40
+ the correct severities and other metadata, they should be written in a
41
+ specific format to a specific location. The logger module in this gem provides
42
+ tools to make that happen.
32
43
 
33
- ## Contributing
44
+ If you are using Ruby on Rails, and you do not otherwise customize your
45
+ Rails logger, then the provided Railtie will direct your logs to the Cloud
46
+ Console "out of the box". Normally, this is configured to take effect when
47
+ running in the `production` environment, but you may also configure it for
48
+ other environments. See the documentation for the `AppEngine::Railtie` class
49
+ for more details.
34
50
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/appengine.
51
+ If you are running a different Rack-based framework such as Sinatra, you
52
+ should install the provided `AppEngine::Logger::Middleware` in your middleware
53
+ stack. This should be installed instead of the normal `Rack::Logger`. It will
54
+ automatically create a logger that directs entries to the Cloud Console, and
55
+ will make it available via the standard `Rack::RACK_LOGGER` key in the Rack
56
+ environment. You may also create your own logger directly using the
57
+ `AppEngine::Logger.create()` method.
36
58
 
59
+ ## Development and support
37
60
 
38
- ## License
61
+ The source code for this gem is available on Github at
62
+ https://github.com/GoogleCloudPlatform/appengine-ruby
39
63
 
40
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
64
+ Report bugs on Github issues at
65
+ https://github.com/GoogleCloudPlatform/appengine-ruby/issues
41
66
 
67
+ Contributions are welcome. Please review the CONTRIBUTING.md file.
data/Rakefile CHANGED
@@ -1,10 +1,36 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
3
15
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList['test/**/*_test.rb']
16
+ require 'bundler/gem_tasks'
17
+ require 'rake/testtask'
18
+ require 'rdoc/task'
19
+
20
+ CLEAN << ['pkg', 'doc']
21
+
22
+ ::Rake::TestTask.new do |t|
23
+ t.libs << 'test'
24
+ t.libs << 'lib'
25
+ t.test_files = ::FileList['test/test_*.rb']
26
+ end
27
+
28
+ ::RDoc::Task.new do |rd|
29
+ rd.rdoc_dir = 'doc'
30
+ rd.main = 'README.md'
31
+ rd.rdoc_files.include 'README.md', 'CONTRIBUTING.md', 'CHANGELOG.md', 'lib/**/*.rb'
32
+ rd.options << '--line-numbers'
33
+ rd.options << '--all'
8
34
  end
9
35
 
10
- task :default => :spec
36
+ task :default => [:test]
data/lib/appengine.rb CHANGED
@@ -1,5 +1,28 @@
1
- require "appengine/version"
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
2
15
 
3
- module Appengine
4
- # Your code goes here...
16
+ # == Google AppEngine integration
17
+ #
18
+ # The AppEngine module includes optional tools helping Ruby applications to
19
+ # integrate more closely with the Google App Engine environment.
20
+
21
+ module AppEngine
5
22
  end
23
+
24
+
25
+ require 'appengine/version'
26
+ require 'appengine/env'
27
+ require 'appengine/logger'
28
+ require 'appengine/railtie' if defined?(::Rails)
@@ -0,0 +1,40 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+
17
+ module AppEngine
18
+
19
+
20
+ # == Environment information
21
+ #
22
+ # A collection of functions for extracting App Engine environment information
23
+ # from the Rack environment
24
+
25
+ module Env
26
+
27
+
28
+ # Returns the Trace ID string from a Rack environment, or nil if no trace
29
+ # ID was found.
30
+
31
+ def self.extract_trace_id(env)
32
+ trace_context = env['HTTP_X_CLOUD_TRACE_CONTEXT'].to_s
33
+ return nil if trace_context.empty?
34
+ return trace_context.sub(/\/.*/, '')
35
+ end
36
+
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,188 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require 'json'
17
+ require 'logger'
18
+
19
+
20
+ module AppEngine
21
+
22
+
23
+ # == AppEngine Logger integration
24
+ #
25
+ # A collection of tools for talking to the StackDriver logs in the Google
26
+ # Cloud Console.
27
+ #
28
+ # For logs to appear in the Google Cloud Console, they must be written in
29
+ # JSON format to files matching the pattern "/var/log/app_engine/app*.json".
30
+ # We provide an appropriate formatter, and a LogDevice that omits the
31
+ # log header line.
32
+ #
33
+ # Logs should also be annotated with the request's Trace ID. We provide
34
+ # a Rack Middleware to extract that ID from the environment and annotate
35
+ # log entries. It uses a fiber-local variable to store the Trace ID for
36
+ # the current request being handled by that fiber.
37
+
38
+ module Logger
39
+
40
+
41
+ # The name of a fiber-local variable storing the trace ID for the current
42
+ # request.
43
+ DEFAULT_TRACE_ID_VAR = :_google_appengine_trace_id
44
+
45
+ # The default path to the log file.
46
+ DEFAULT_LOG_FILENAME = '/var/log/app_engine/app-ruby.json'
47
+
48
+ # A map from Ruby severity names to Google Cloud severity names.
49
+ SEV_MAP = {
50
+ 'DEBUG' => 'DEBUG',
51
+ 'INFO' => 'INFO',
52
+ 'WARN' => 'WARNING',
53
+ 'ERROR' => 'ERROR',
54
+ 'FATAL' => 'CRITICAL'
55
+ }
56
+
57
+
58
+ # == AppEngie Formatter
59
+ #
60
+ # A formatter that generates the appropriate JSON format for log entries.
61
+ # Pulls the trace ID from the fiber-local variable, if present.
62
+ #
63
+ # (see ::Logger::Formatter)
64
+
65
+ class Formatter
66
+
67
+
68
+ # Create a new formatter. You may optionally override the fiber-local
69
+ # variable name used for the trace ID.
70
+
71
+ def initialize(trace_id_var: DEFAULT_TRACE_ID_VAR)
72
+ @trace_id_var = trace_id_var
73
+ end
74
+
75
+
76
+ def call(severity, time, progname, msg) # :nodoc:
77
+ msg = msg.to_s
78
+ return '' if msg.empty?
79
+ entry = {
80
+ message: (progname.to_s != '') ? "#{progname}: #{msg}" : msg,
81
+ timestamp: {seconds: time.to_i, nanos: time.nsec},
82
+ severity: SEV_MAP.fetch(severity.to_s, 'CRITICAL')
83
+ }
84
+ trace_id = ::Thread.current[@trace_id_var]
85
+ if trace_id
86
+ entry[:traceId] = trace_id.to_s
87
+ end
88
+ ::JSON.generate(entry) + "\n"
89
+ end
90
+
91
+ end
92
+
93
+
94
+ # == AppEngine LogDevice
95
+ #
96
+ # A ::Logger::LogDevice subclass that omits the log header line.
97
+
98
+ class LogDevice < ::Logger::LogDevice
99
+
100
+ def add_log_header(file) # :nodoc:
101
+ end
102
+
103
+ end
104
+
105
+
106
+ # == Rack Middleware for AppEngine logger
107
+ #
108
+ # A Rack middleware that sets the logger in the Rack environment, and
109
+ # stashes the trace ID for the current request in a fiber-local variable
110
+ # for the logger to use when formatting log entries.
111
+ #
112
+ # In a standard Rack application, you should use this middleware instead
113
+ # of the standard ::Rack::Logger.
114
+
115
+ class Middleware
116
+
117
+
118
+ # Create a new AppEngine logging Middleware.
119
+ # The argument is an options hash supporting the following keys:
120
+ #
121
+ # [<tt>:logger</tt>]
122
+ # A global logger to use. This should generally be a logger created
123
+ # by AppEngine::Logger.create(). The middleware sets env["rack.logger"]
124
+ # accordingly. If omitted, a default logger is created automatically
125
+ # when the middleware is constructed.
126
+ # [<tt>:trace_id_var</tt>]
127
+ # The name of the fiber-local variable to use to stack the trace ID.
128
+ # Defaults to the value of DEFAULT_TRACE_ID_VAR. You generally should
129
+ # not need to modify this value unless you need to control fiber-local
130
+ # variable names.
131
+ # [<tt>:logfile</tt>]
132
+ # If you do not specify a <tt>:logger</tt>, a logger is created that
133
+ # opens this file. Defaults to the value of DEFAULT_LOG_FILENAME.
134
+ # Generally, you should leave this setting to the default for
135
+ # deployments, because App Engine expects log files in a particular
136
+ # location. However, if you want to test log generation into a
137
+ # different directory in development, you may set it here.
138
+
139
+ def initialize(app,
140
+ logger: nil,
141
+ trace_id_var: DEFAULT_TRACE_ID_VAR,
142
+ logfile: DEFAULT_LOG_FILENAME)
143
+ @app = app
144
+ @trace_id_var = trace_id_var
145
+ @logger = logger || Logger.create(trace_id_var: trace_id_var, logfile: logfile)
146
+ end
147
+
148
+
149
+ def call(env) # :nodoc:
150
+ env['rack.logger'] = @logger
151
+ ::Thread.current[@trace_id_var] = Env.extract_trace_id(env)
152
+ begin
153
+ @app.call(env)
154
+ ensure
155
+ ::Thread.current[@trace_id_var] = nil
156
+ end
157
+ end
158
+
159
+ end
160
+
161
+
162
+ # Creates a new logger for AppEngine that writes to the correct location
163
+ # using the correct formatting.
164
+ # The argument is an options hash supporting the following keys:
165
+ #
166
+ # [<tt>:trace_id_var</tt>]
167
+ # The name of the fiber-local variable to use to stack the trace ID.
168
+ # Defaults to the value of DEFAULT_TRACE_ID_VAR. You generally should
169
+ # not need to modify this value unless you need to control fiber-local
170
+ # variable names.
171
+ # [<tt>:logfile</tt>]
172
+ # Log file to write to. Defaults to the value of DEFAULT_LOG_FILENAME.
173
+ # Generally, you should leave this setting to the default for
174
+ # deployments, because App Engine expects log files in a particular
175
+ # location. However, if you want to test log generation into a
176
+ # different directory in development, you may set it here.
177
+
178
+ def self.create(trace_id_var: DEFAULT_TRACE_ID_VAR, logfile: DEFAULT_LOG_FILENAME)
179
+ if logfile.kind_of?(::String)
180
+ ::FileUtils.mkdir_p(::File.dirname(logfile))
181
+ end
182
+ logger = ::Logger.new(LogDevice.new(logfile))
183
+ logger.formatter = Formatter.new(trace_id_var: trace_id_var)
184
+ logger
185
+ end
186
+
187
+ end
188
+ end
@@ -0,0 +1,84 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require 'fileutils'
17
+
18
+
19
+ module AppEngine
20
+
21
+
22
+ # == AppEngine Rails integration
23
+ #
24
+ # A Railtie providing Rails integration with the Google App Engine runtime
25
+ # environment. Sets up the Rails logger to log to the Google Cloud Console
26
+ # in production.
27
+ #
28
+ # To use, just include the "appengine" gem in your gemfile, and make sure
29
+ # it is required in your config/application.rb (if you are not already
30
+ # using Bundler.require).
31
+ #
32
+ # === Configuration
33
+ #
34
+ # The following configuration parameters are supported.
35
+ #
36
+ # [<tt>config.appengine.use_cloud_logger</tt>]
37
+ # Set to true to cause the Rails logger to log to Google Cloud Console.
38
+ # By default, this is true in the production environment and false in
39
+ # all other environments. You may override this setting in individual
40
+ # environment config files.
41
+ #
42
+ # [<tt>config.appengine.logfile</tt>]
43
+ # The path to the log file when <tt>use_cloud_logger</tt> is active.
44
+ # You should normally leave this as the default when deploying to Google
45
+ # App Engine, but you may set it to a different path if you want to test
46
+ # logging in a development environment.
47
+ #
48
+ # [<tt>config.appengine.trace_id_var</tt>]
49
+ # The name of a fiber-local variable to store the current request's trace
50
+ # ID. This is used to communicate request and trace information between
51
+ # Rack and the cloud logger. You may change it if you need to control
52
+ # fiber-local variable names.
53
+
54
+ class Railtie < ::Rails::Railtie
55
+
56
+ # :stopdoc:
57
+
58
+ config.appengine = ::ActiveSupport::OrderedOptions.new
59
+
60
+ config.appengine.use_cloud_logger = ::Rails.env.to_s == 'production'
61
+ config.appengine.logfile = ::AppEngine::Logger::DEFAULT_LOG_FILENAME
62
+ config.appengine.trace_id_var = ::AppEngine::Logger::DEFAULT_TRACE_ID_VAR
63
+
64
+
65
+ initializer 'google.appengine.logger', before: :initialize_logger do |app|
66
+ if app.config.appengine.use_cloud_logger
67
+ app.config.logger = ::AppEngine::Logger.create(
68
+ logfile: app.config.appengine.logfile,
69
+ trace_id_var: app.config.appengine.trace_id_var)
70
+ app.config.log_formatter = app.config.logger.formatter
71
+
72
+ app.middleware.insert_before(::Rails::Rack::Logger,
73
+ ::AppEngine::Logger::Middleware,
74
+ logger: app.config.logger,
75
+ trace_id_var: app.config.appengine.trace_id_var)
76
+ end
77
+ end
78
+
79
+ # :startdoc:
80
+
81
+ end
82
+
83
+
84
+ end
@@ -1,3 +1,21 @@
1
- module Appengine
2
- VERSION = "0.1.1"
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ module AppEngine
17
+
18
+ # The current version of this gem, as a string.
19
+ VERSION = '0.2.0'.freeze
20
+
3
21
  end
data/test/test_env.rb ADDED
@@ -0,0 +1,57 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require 'minitest/autorun'
17
+ require 'appengine'
18
+
19
+
20
+ module AppEngine
21
+ module Tests # :nodoc:
22
+
23
+ class TestEnv < ::Minitest::Test # :nodoc:
24
+
25
+
26
+ def test_extract_trace_id_absent
27
+ env = {}
28
+ trace_id = Env.extract_trace_id(env)
29
+ assert_nil(trace_id)
30
+ end
31
+
32
+
33
+ def test_extract_trace_id_empty
34
+ env = {'HTTP_X_CLOUD_TRACE_CONTEXT' => ''}
35
+ trace_id = Env.extract_trace_id(env)
36
+ assert_nil(trace_id)
37
+ end
38
+
39
+
40
+ def test_extract_trace_id_simple
41
+ env = {'HTTP_X_CLOUD_TRACE_CONTEXT' => 'abcdefg'}
42
+ trace_id = Env.extract_trace_id(env)
43
+ assert_equal('abcdefg', trace_id)
44
+ end
45
+
46
+
47
+ def test_extract_trace_id_with_suffix
48
+ env = {'HTTP_X_CLOUD_TRACE_CONTEXT' => 'abcdefg/hijk/lmnop'}
49
+ trace_id = Env.extract_trace_id(env)
50
+ assert_equal('abcdefg', trace_id)
51
+ end
52
+
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,151 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ ;
15
+
16
+ require 'minitest/autorun'
17
+ require 'appengine'
18
+
19
+
20
+ module AppEngine
21
+ module Tests # :nodoc:
22
+
23
+ class TestFormatter < ::Minitest::Test # :nodoc:
24
+
25
+
26
+ def setup
27
+ @time_sec = 1461544128
28
+ @time_nsec = 580791000
29
+ @time = ::Time.at(@time_sec, @time_nsec / 1000)
30
+ @trace_id = 'a1b2c3d4e5f6'
31
+ ::Thread.current[::AppEngine::Logger::DEFAULT_TRACE_ID_VAR] = @trace_id
32
+ @formatter = ::AppEngine::Logger::Formatter.new
33
+ end
34
+
35
+
36
+ def test_format_empty
37
+ result = @formatter.call('ERROR', @time, 'prog', '')
38
+ assert_equal('', result)
39
+ end
40
+
41
+
42
+ def test_format_with_progname
43
+ result = @formatter.call('ERROR', @time, 'prog', 'this message')
44
+ assert_equal(
45
+ "{\"message\":\"prog: this message\"," +
46
+ "\"timestamp\":{\"seconds\":#{@time_sec},\"nanos\":#{@time_nsec}}," +
47
+ "\"severity\":\"ERROR\"," +
48
+ "\"traceId\":\"#{@trace_id}\"}\n",
49
+ result)
50
+ end
51
+
52
+
53
+ def test_format_with_no_trace_id
54
+ ::Thread.current[::AppEngine::Logger::DEFAULT_TRACE_ID_VAR] = nil
55
+ result = @formatter.call('ERROR', @time, '', 'this message')
56
+ assert_equal(
57
+ "{\"message\":\"this message\"," +
58
+ "\"timestamp\":{\"seconds\":#{@time_sec},\"nanos\":#{@time_nsec}}," +
59
+ "\"severity\":\"ERROR\"}\n",
60
+ result)
61
+ end
62
+
63
+
64
+ def test_format_with_warning_severity
65
+ result = @formatter.call('WARN', @time, '', 'this message')
66
+ assert_equal(
67
+ "{\"message\":\"this message\"," +
68
+ "\"timestamp\":{\"seconds\":#{@time_sec},\"nanos\":#{@time_nsec}}," +
69
+ "\"severity\":\"WARNING\"," +
70
+ "\"traceId\":\"#{@trace_id}\"}\n",
71
+ result)
72
+ end
73
+
74
+
75
+ def test_format_with_critical_severity
76
+ result = @formatter.call('FATAL', @time, '', 'this message')
77
+ assert_equal(
78
+ "{\"message\":\"this message\"," +
79
+ "\"timestamp\":{\"seconds\":#{@time_sec},\"nanos\":#{@time_nsec}}," +
80
+ "\"severity\":\"CRITICAL\"," +
81
+ "\"traceId\":\"#{@trace_id}\"}\n",
82
+ result)
83
+ end
84
+
85
+
86
+ def test_format_with_unknown_severity
87
+ result = @formatter.call('UNKNOWN', @time, '', 'this message')
88
+ assert_equal(
89
+ "{\"message\":\"this message\"," +
90
+ "\"timestamp\":{\"seconds\":#{@time_sec},\"nanos\":#{@time_nsec}}," +
91
+ "\"severity\":\"CRITICAL\"," +
92
+ "\"traceId\":\"#{@trace_id}\"}\n",
93
+ result)
94
+ end
95
+
96
+
97
+ end
98
+
99
+
100
+ class TestLogger < ::Minitest::Test # :nodoc:
101
+
102
+
103
+ def test_no_logging
104
+ lines = run_test do |logger|
105
+ end
106
+ assert_equal([], lines)
107
+ end
108
+
109
+
110
+ def test_basic_log
111
+ trace_id = "tracetrace"
112
+ lines = run_test(trace_id) do |logger|
113
+ logger.progname = "rails"
114
+ logger.info("Hello")
115
+ logger.warn("This is a warning")
116
+ end
117
+ assert_equal(2, lines.size)
118
+ assert_log_entry("rails: Hello", "INFO", trace_id, lines[0])
119
+ assert_log_entry("rails: This is a warning", "WARNING", trace_id, lines[1])
120
+ end
121
+
122
+
123
+ def assert_log_entry(expected_message, expected_severity, expected_trace_id, line)
124
+ if line =~ /^\{"message":"(.*)","timestamp":\{"seconds":\d+,"nanos":\d+\},"severity":"(\w+)"(,"traceId":"(\w+)")?\}\n$/
125
+ message = $1
126
+ severity = $2
127
+ trace_id = $4
128
+ assert_equal(expected_message, message)
129
+ assert_equal(expected_severity, severity)
130
+ assert_equal(expected_trace_id, trace_id)
131
+ else
132
+ flunk("Bad format: #{line.inspect}")
133
+ end
134
+ end
135
+
136
+
137
+ def run_test(trace_id=nil)
138
+ stringio = ::StringIO.new('', 'w')
139
+ app = ::Proc.new { |env|
140
+ yield(env['rack.logger'])
141
+ }
142
+ middleware = ::AppEngine::Logger::Middleware.new(app, logfile: stringio)
143
+ middleware.call({'HTTP_X_CLOUD_TRACE_CONTEXT' => trace_id})
144
+ ::StringIO.new(stringio.string).each_line.to_a
145
+ end
146
+
147
+
148
+ end
149
+
150
+ end
151
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Tanner
8
8
  - Daniel Azuma
9
9
  autorequire:
10
- bindir: exe
10
+ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2016-05-04 00:00:00.000000000 Z
13
13
  dependencies:
@@ -15,86 +15,103 @@ dependencies:
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.11'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ~>
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.11'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '5.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '5.0'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: rake
30
44
  requirement: !ruby/object:Gem::Requirement
31
45
  requirements:
32
- - - ~>
46
+ - - "~>"
33
47
  - !ruby/object:Gem::Version
34
- version: '10.0'
48
+ version: '11.0'
35
49
  type: :development
36
50
  prerelease: false
37
51
  version_requirements: !ruby/object:Gem::Requirement
38
52
  requirements:
39
- - - ~>
53
+ - - "~>"
40
54
  - !ruby/object:Gem::Version
41
- version: '10.0'
55
+ version: '11.0'
42
56
  - !ruby/object:Gem::Dependency
43
- name: minitest
57
+ name: rdoc
44
58
  requirement: !ruby/object:Gem::Requirement
45
59
  requirements:
46
- - - ~>
60
+ - - "~>"
47
61
  - !ruby/object:Gem::Version
48
- version: '5.0'
62
+ version: '4.2'
49
63
  type: :development
50
64
  prerelease: false
51
65
  version_requirements: !ruby/object:Gem::Requirement
52
66
  requirements:
53
- - - ~>
67
+ - - "~>"
54
68
  - !ruby/object:Gem::Version
55
- version: '5.0'
56
- description: ''
69
+ version: '4.2'
70
+ description: The appengine gem is a set of classes, plugins, and tools for integration
71
+ with Google App Engine. It provides access to the App Engine runtime environment,
72
+ including logging to the Google Cloud Console and interpretation of App Engine headers.
73
+ However, it is not required for deploying your Ruby application to App Engine.
57
74
  email:
58
75
  - adamtanner@google.com
59
- - dazuma@google.com
76
+ - dazuma@gmail.com
60
77
  executables: []
61
78
  extensions: []
62
79
  extra_rdoc_files: []
63
80
  files:
64
- - .gitignore
65
- - .travis.yml
66
- - Gemfile
81
+ - CHANGELOG.md
82
+ - CONTRIBUTING.md
67
83
  - LICENSE
68
84
  - README.md
69
85
  - Rakefile
70
- - appengine.gemspec
71
- - bin/console
72
- - bin/setup
73
86
  - lib/appengine.rb
87
+ - lib/appengine/env.rb
88
+ - lib/appengine/logger.rb
89
+ - lib/appengine/railtie.rb
74
90
  - lib/appengine/version.rb
75
- homepage: ''
91
+ - test/test_env.rb
92
+ - test/test_logger.rb
93
+ homepage: https://github.com/GoogleCloudPlatform/appengine-ruby
76
94
  licenses:
77
95
  - Apache 2.0
78
- metadata:
79
- allowed_push_host: 'TODO: Set to ''http://mygemserver.com'''
96
+ metadata: {}
80
97
  post_install_message:
81
98
  rdoc_options: []
82
99
  require_paths:
83
100
  - lib
84
101
  required_ruby_version: !ruby/object:Gem::Requirement
85
102
  requirements:
86
- - - '>='
103
+ - - ">="
87
104
  - !ruby/object:Gem::Version
88
- version: '0'
105
+ version: 2.0.0
89
106
  required_rubygems_version: !ruby/object:Gem::Requirement
90
107
  requirements:
91
- - - '>='
108
+ - - ">="
92
109
  - !ruby/object:Gem::Version
93
110
  version: '0'
94
111
  requirements: []
95
112
  rubyforge_project:
96
- rubygems_version: 2.0.14.1
113
+ rubygems_version: 2.4.5.1
97
114
  signing_key:
98
115
  specification_version: 4
99
- summary: ''
116
+ summary: Google App Engine integration tools
100
117
  test_files: []
data/.gitignore DELETED
@@ -1,9 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.0.0
4
- before_install: gem install bundler -v 1.11.2
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in appengine.gemspec
4
- gemspec
data/appengine.gemspec DELETED
@@ -1,33 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'appengine/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "appengine"
8
- spec.version = Appengine::VERSION
9
- spec.authors = ["Adam Tanner", "Daniel Azuma"]
10
- spec.email = ["adamtanner@google.com", "dazuma@google.com"]
11
-
12
- spec.summary = ""
13
- spec.description = ""
14
- spec.homepage = ""
15
- spec.license = "Apache 2.0"
16
-
17
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
- # delete this section to allow pushing this gem to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
- else
22
- raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 1.11"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency "minitest", "~> 5.0"
33
- end
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "appengine"
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
data/bin/setup DELETED
@@ -1,8 +0,0 @@
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