gemstash 1.0.4 → 1.1.0

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.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +33 -0
  3. data/lib/gemstash.rb +2 -0
  4. data/lib/gemstash/api_key_authorization.rb +29 -0
  5. data/lib/gemstash/authorization.rb +5 -1
  6. data/lib/gemstash/cli/authorize.rb +1 -1
  7. data/lib/gemstash/cli/setup.rb +50 -37
  8. data/lib/gemstash/cli/start.rb +1 -1
  9. data/lib/gemstash/config.ru +1 -0
  10. data/lib/gemstash/configuration.rb +35 -3
  11. data/lib/gemstash/db/version.rb +11 -0
  12. data/lib/gemstash/env.rb +16 -10
  13. data/lib/gemstash/gem_fetcher.rb +1 -1
  14. data/lib/gemstash/gem_pusher.rb +15 -17
  15. data/lib/gemstash/gem_source/private_source.rb +29 -44
  16. data/lib/gemstash/gem_source/upstream_source.rb +4 -4
  17. data/lib/gemstash/gem_unyanker.rb +10 -4
  18. data/lib/gemstash/gem_yanker.rb +10 -4
  19. data/lib/gemstash/health.rb +53 -0
  20. data/lib/gemstash/http_client.rb +5 -3
  21. data/lib/gemstash/logging.rb +1 -1
  22. data/lib/gemstash/man/gemstash-authorize.1 +6 -5
  23. data/lib/gemstash/man/gemstash-authorize.1.txt +14 -13
  24. data/lib/gemstash/man/gemstash-configuration.5 +90 -8
  25. data/lib/gemstash/man/gemstash-configuration.5.txt +82 -6
  26. data/lib/gemstash/man/gemstash-customize.7 +68 -12
  27. data/lib/gemstash/man/gemstash-customize.7.txt +64 -26
  28. data/lib/gemstash/man/gemstash-debugging.7 +1 -1
  29. data/lib/gemstash/man/gemstash-deploy.7 +33 -1
  30. data/lib/gemstash/man/gemstash-deploy.7.txt +25 -0
  31. data/lib/gemstash/man/gemstash-mirror.7 +1 -1
  32. data/lib/gemstash/man/gemstash-multiple-sources.7 +1 -1
  33. data/lib/gemstash/man/gemstash-private-gems.7 +52 -3
  34. data/lib/gemstash/man/gemstash-private-gems.7.txt +39 -4
  35. data/lib/gemstash/man/gemstash-readme.7 +34 -4
  36. data/lib/gemstash/man/gemstash-readme.7.txt +34 -12
  37. data/lib/gemstash/man/gemstash-setup.1 +3 -1
  38. data/lib/gemstash/man/gemstash-setup.1.txt +3 -1
  39. data/lib/gemstash/man/gemstash-start.1 +4 -3
  40. data/lib/gemstash/man/gemstash-start.1.txt +5 -4
  41. data/lib/gemstash/man/gemstash-status.1 +4 -3
  42. data/lib/gemstash/man/gemstash-status.1.txt +3 -2
  43. data/lib/gemstash/man/gemstash-stop.1 +4 -3
  44. data/lib/gemstash/man/gemstash-stop.1.txt +3 -2
  45. data/lib/gemstash/man/gemstash-version.1 +1 -1
  46. data/lib/gemstash/puma.rb +2 -2
  47. data/lib/gemstash/specs_builder.rb +14 -16
  48. data/lib/gemstash/version.rb +1 -1
  49. metadata +29 -7
@@ -6,6 +6,7 @@ module Gemstash
6
6
  class PrivateSource < Gemstash::GemSource::Base
7
7
  include Gemstash::GemSource::DependencyCaching
8
8
  include Gemstash::Env::Helper
9
+ attr_accessor :auth
9
10
 
10
11
  def self.rack_env_rewriter
11
12
  @rack_env_rewriter ||= Gemstash::RackEnvRewriter.new(%r{\A/private})
@@ -23,27 +24,15 @@ module Gemstash
23
24
  end
24
25
 
25
26
  def serve_add_gem
26
- authenticated("Gemstash Private Gems") do
27
- auth = request.env["HTTP_AUTHORIZATION"]
28
- gem = request.body.read
29
- Gemstash::GemPusher.new(auth, gem).push
30
- end
27
+ protected(Gemstash::GemPusher)
31
28
  end
32
29
 
33
30
  def serve_yank
34
- authenticated("Gemstash Private Gems") do
35
- auth = request.env["HTTP_AUTHORIZATION"]
36
- gem_name = params[:gem_name]
37
- Gemstash::GemYanker.new(auth, gem_name, slug_param).yank
38
- end
31
+ protected(Gemstash::GemYanker)
39
32
  end
40
33
 
41
34
  def serve_unyank
42
- authenticated("Gemstash Private Gems") do
43
- auth = request.env["HTTP_AUTHORIZATION"]
44
- gem_name = params[:gem_name]
45
- Gemstash::GemUnyanker.new(auth, gem_name, slug_param).unyank
46
- end
35
+ protected(Gemstash::GemUnyanker)
47
36
  end
48
37
 
49
38
  def serve_add_spec_json
@@ -67,11 +56,14 @@ module Gemstash
67
56
  end
68
57
 
69
58
  def serve_marshal(id)
70
- gem_full_name = id.sub(/\.gemspec\.rz\z/, "")
71
- gem = fetch_gem(gem_full_name)
72
- halt 404 unless gem.exist?(:spec)
73
- content_type "application/octet-stream"
74
- gem.content(:spec)
59
+ authorization.protect(self) do
60
+ auth.check("fetch") if gemstash_env.config[:protected_fetch]
61
+ gem_full_name = id.sub(/\.gemspec\.rz\z/, "")
62
+ gem = fetch_gem(gem_full_name)
63
+ halt 404 unless gem.exist?(:spec)
64
+ content_type "application/octet-stream"
65
+ gem.content(:spec)
66
+ end
75
67
  end
76
68
 
77
69
  def serve_actual_gem(id)
@@ -79,45 +71,38 @@ module Gemstash
79
71
  end
80
72
 
81
73
  def serve_gem(id)
82
- gem_full_name = id.sub(/\.gem\z/, "")
83
- gem = fetch_gem(gem_full_name)
84
- content_type "application/octet-stream"
85
- gem.content(:gem)
74
+ authorization.protect(self) do
75
+ auth.check("fetch") if gemstash_env.config[:protected_fetch]
76
+ gem_full_name = id.sub(/\.gem\z/, "")
77
+ gem = fetch_gem(gem_full_name)
78
+ content_type "application/octet-stream"
79
+ gem.content(:gem)
80
+ end
86
81
  end
87
82
 
88
83
  def serve_specs
89
- content_type "application/octet-stream"
90
- Gemstash::SpecsBuilder.all
84
+ params[:prerelease] = false
85
+ protected(Gemstash::SpecsBuilder)
91
86
  end
92
87
 
93
88
  def serve_latest_specs
94
- content_type "application/octet-stream"
95
- Gemstash::SpecsBuilder.latest
89
+ params[:latest] = true
90
+ protected(Gemstash::SpecsBuilder)
96
91
  end
97
92
 
98
93
  def serve_prerelease_specs
99
- content_type "application/octet-stream"
100
- Gemstash::SpecsBuilder.prerelease
94
+ params[:prerelease] = true
95
+ protected(Gemstash::SpecsBuilder)
101
96
  end
102
97
 
103
98
  private
104
99
 
105
- def slug_param
106
- version = params[:version]
107
- platform = params[:platform]
108
-
109
- if platform.to_s.empty?
110
- version
111
- else
112
- "#{version}-#{platform}"
113
- end
100
+ def protected(servable)
101
+ authorization.protect(self) { servable.serve(self) }
114
102
  end
115
103
 
116
- def authenticated(realm)
117
- yield
118
- rescue Gemstash::NotAuthorizedError => e
119
- headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
120
- halt 401, e.message
104
+ def authorization
105
+ Gemstash::ApiKeyAuthorization
121
106
  end
122
107
 
123
108
  def dependencies
@@ -196,13 +196,13 @@ module Gemstash
196
196
  # default upstream).
197
197
  class RubygemsSource < Gemstash::GemSource::UpstreamSource
198
198
  def self.matches?(env)
199
- if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
200
- env["gemstash.upstream"] = env["gemstash.env"].config[:rubygems_url]
199
+ env["gemstash.upstream"] = if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
200
+ env["gemstash.env"].config[:rubygems_url]
201
201
  else
202
- env["gemstash.upstream"] = env["HTTP_X_GEMFILE_SOURCE"]
202
+ env["HTTP_X_GEMFILE_SOURCE"]
203
203
  end
204
- capture_user_agent(env)
205
204
 
205
+ capture_user_agent(env)
206
206
  true
207
207
  end
208
208
  end
@@ -17,13 +17,19 @@ module Gemstash
17
17
  class NotYankedVersionError < StandardError
18
18
  end
19
19
 
20
- def initialize(auth_key, gem_name, slug)
21
- @auth_key = auth_key
20
+ def self.serve(app)
21
+ gem_name = app.params[:gem_name]
22
+ slug = Gemstash::DB::Version.slug(app.params)
23
+ new(app.auth, gem_name, slug).serve
24
+ end
25
+
26
+ def initialize(auth, gem_name, slug)
27
+ @auth = auth
22
28
  @gem_name = gem_name
23
29
  @slug = slug
24
30
  end
25
31
 
26
- def unyank
32
+ def serve
27
33
  check_auth
28
34
  update_database
29
35
  invalidate_cache
@@ -40,7 +46,7 @@ module Gemstash
40
46
  end
41
47
 
42
48
  def check_auth
43
- Gemstash::Authorization.check(@auth_key, "unyank")
49
+ @auth.check("unyank")
44
50
  end
45
51
 
46
52
  def update_database
@@ -17,13 +17,19 @@ module Gemstash
17
17
  class YankedVersionError < StandardError
18
18
  end
19
19
 
20
- def initialize(auth_key, gem_name, slug)
21
- @auth_key = auth_key
20
+ def self.serve(app)
21
+ gem_name = app.params[:gem_name]
22
+ slug = Gemstash::DB::Version.slug(app.params)
23
+ new(app.auth, gem_name, slug).serve
24
+ end
25
+
26
+ def initialize(auth, gem_name, slug)
27
+ @auth = auth
22
28
  @gem_name = gem_name
23
29
  @slug = slug
24
30
  end
25
31
 
26
- def yank
32
+ def serve
27
33
  check_auth
28
34
  update_database
29
35
  invalidate_cache
@@ -40,7 +46,7 @@ module Gemstash
40
46
  end
41
47
 
42
48
  def check_auth
43
- Gemstash::Authorization.check(@auth_key, "yank")
49
+ @auth.check("yank")
44
50
  end
45
51
 
46
52
  def update_database
@@ -0,0 +1,53 @@
1
+ require "gemstash"
2
+ require "date"
3
+ require "server_health_check_rack"
4
+ require "sequel"
5
+
6
+ module Gemstash
7
+ # This module contains the logic used to supply a health monitor for
8
+ # Gemstash. You can access the health monitor at the /health endpoint.
9
+ module Health
10
+ # This check can be used if you don't want to read or write content during a
11
+ # health check.
12
+ def self.heartbeat
13
+ true
14
+ end
15
+
16
+ def self.check_storage_read
17
+ if check_storage_write
18
+ content = Gemstash::Storage.for("health").resource("test").content(:example)
19
+ content =~ /\Acontent-\d+\z/
20
+ end
21
+ end
22
+
23
+ def self.check_storage_write
24
+ resource = Gemstash::Storage.for("health").resource("test")
25
+ resource.save(example: "content-#{Time.now.to_i}")
26
+ true
27
+ end
28
+
29
+ def self.check_db_read
30
+ result = Gemstash::Env.current.db[:rubygems].where(name: "testing_db_read").count
31
+ result.is_a?(Numeric)
32
+ end
33
+
34
+ def self.check_db_write
35
+ Gemstash::Env.current.db.transaction do
36
+ Gemstash::Env.current.db[:rubygems].insert(name: "health_check:fake_gem_name",
37
+ created_at: DateTime.now,
38
+ updated_at: DateTime.now)
39
+ # We don't want to actually write to the database
40
+ raise Sequel::Rollback
41
+ end
42
+
43
+ true
44
+ end
45
+
46
+ ServerHealthCheckRack::Checks.check("heartbeat") { Gemstash::Health.heartbeat }
47
+ ServerHealthCheckRack::Checks.check("storage_read") { Gemstash::Health.check_storage_read }
48
+ ServerHealthCheckRack::Checks.check("storage_write") { Gemstash::Health.check_storage_write }
49
+ ServerHealthCheckRack::Checks.check("db_read") { Gemstash::Health.check_db_read }
50
+ ServerHealthCheckRack::Checks.check("db_write") { Gemstash::Health.check_db_write }
51
+ RackMiddleware = ServerHealthCheckRack::Middleware
52
+ end
53
+ end
@@ -22,14 +22,16 @@ module Gemstash
22
22
 
23
23
  #:nodoc:
24
24
  class HTTPClient
25
+ extend Gemstash::Env::Helper
25
26
  include Gemstash::Logging
26
27
 
27
- DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}"
28
+ DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}".freeze
28
29
 
29
30
  def self.for(upstream)
30
31
  client = Faraday.new(upstream.to_s) do |config|
31
32
  config.use FaradayMiddleware::FollowRedirects
32
33
  config.adapter :net_http
34
+ config.options.timeout = gemstash_env.config[:fetch_timeout]
33
35
  end
34
36
  user_agent = "#{upstream.user_agent} " unless upstream.user_agent.to_s.empty?
35
37
  user_agent = user_agent.to_s + DEFAULT_USER_AGENT
@@ -61,11 +63,11 @@ module Gemstash
61
63
 
62
64
  private
63
65
 
64
- def with_retries(times: 3, &block)
66
+ def with_retries(times: 3)
65
67
  loop do
66
68
  times -= 1
67
69
  begin
68
- return block.call
70
+ return yield
69
71
  rescue Faraday::ConnectionFailed => e
70
72
  log_error("Connection failure", e)
71
73
  raise(ConnectionError, e.message) unless times > 0
@@ -10,7 +10,7 @@ module Gemstash
10
10
  warn: Logger::WARN,
11
11
  error: Logger::ERROR,
12
12
  fatal: Logger::FATAL
13
- }
13
+ }.freeze
14
14
 
15
15
  def log
16
16
  Gemstash::Logging.logger
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pandoc 1.16.0.2
1
+ .\" Automatically generated by Pandoc 1.19.2.1
2
2
  .\"
3
3
  .TH "gemstash\-authorize" "1" "October 9, 2015" "" ""
4
4
  .hy
@@ -14,8 +14,8 @@ privately stored gems
14
14
  Adds or removes authorization to interact with privately stored gems.
15
15
  .PP
16
16
  Any arguments will be used as specific permissions.
17
- Valid permissions include \f[C]push\f[], \f[C]yank\f[], and
18
- \f[C]unyank\f[].
17
+ Valid permissions include \f[C]push\f[], \f[C]yank\f[], \f[C]unyank\f[],
18
+ and \f[C]fetch\f[].
19
19
  If no permissions are provided, then all permissions will be granted
20
20
  (including any that may be added in future versions of Gemstash).
21
21
  .SS USAGE
@@ -32,8 +32,9 @@ gemstash\ authorize\ \-\-remove\ \-\-key\ <secure\-key>
32
32
  .IP \[bu] 2
33
33
  \f[C]\-\-config\-file\ FILE\f[]: Specify the config file to use.
34
34
  If you aren\[aq]t using the default config file at
35
- \f[C]~/.gemstash/config.yml\f[], then you must specify the config file
36
- via this option.
35
+ \f[C]~/.gemstash/config.yml\f[] or
36
+ \f[C]~/.gemstash/config.yml.erb\f[] (gemstash help customize.7), then
37
+ you must specify the config file via this option.
37
38
  .IP \[bu] 2
38
39
  \f[C]\-\-key\ SECURE_KEY\f[]: Specify the API key to affect.
39
40
  This should be the actual key value, not a name.
@@ -14,9 +14,9 @@ DESCRIPTION
14
14
  Adds or removes authorization to interact with privately stored gems.
15
15
 
16
16
  Any arguments will be used as specific permissions. Valid permissions
17
- include push, yank, and unyank. If no permissions are provided, then
18
- all permissions will be granted (including any that may be added in fu-
19
- ture versions of Gemstash).
17
+ include push, yank, unyank, and fetch. If no permissions are provided,
18
+ then all permissions will be granted (including any that may be added
19
+ in future versions of Gemstash).
20
20
 
21
21
  USAGE
22
22
  gemstash authorize
@@ -26,18 +26,19 @@ DESCRIPTION
26
26
 
27
27
  OPTIONS
28
28
  o --config-file FILE: Specify the config file to use. If you aren't
29
- using the default config file at ~/.gemstash/config.yml, then you
30
- must specify the config file via this option.
31
-
32
- o --key SECURE_KEY: Specify the API key to affect. This should be the
33
- actual key value, not a name. This option is required when using
34
- --remove but is optional otherwise. If adding an authorization, us-
35
- ing this will either create or update the permissions for the speci-
36
- fied API key. If missing, a new API key will always be generated.
29
+ using the default config file at ~/.gemstash/config.yml or ~/.gem-
30
+ stash/config.yml.erb (gemstash help customize.7), then you must spec-
31
+ ify the config file via this option.
32
+
33
+ o --key SECURE_KEY: Specify the API key to affect. This should be the
34
+ actual key value, not a name. This option is required when using
35
+ --remove but is optional otherwise. If adding an authorization, us-
36
+ ing this will either create or update the permissions for the speci-
37
+ fied API key. If missing, a new API key will always be generated.
37
38
  Note that a key can only have a maximum length of 255 chars.
38
39
 
39
- o --remove: Remove an authorization rather than add or update one.
40
- When removing, permission values are not allowed. The --key <se-
40
+ o --remove: Remove an authorization rather than add or update one.
41
+ When removing, permission values are not allowed. The --key <se-
41
42
  cure-key> option is required.
42
43
 
43
44
 
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pandoc 1.16.0.2
1
+ .\" Automatically generated by Pandoc 1.19.2.1
2
2
  .\"
3
3
  .TH "gemstash\-configuration" "5" "October 13, 2015" "" ""
4
4
  .hy
@@ -16,8 +16,15 @@ gemstash\-configuration
16
16
  :memcached_servers:\ localhost:11211
17
17
  :db_adapter:\ postgres
18
18
  :db_url:\ postgres:///gemstash
19
+ :db_connection_options:
20
+ \ \ :test:\ true
21
+ \ \ :pool_timeout:\ 2
19
22
  :rubygems_url:\ https://my.gem\-source.local
23
+ :puma_threads:\ 32
20
24
  :bind:\ tcp://0.0.0.0:4242
25
+ :protected_fetch:\ true
26
+ :fetch_timeout:\ 10
27
+ :log_file:\ gemstash.log
21
28
  \f[]
22
29
  .fi
23
30
  .SH BASE PATH
@@ -77,28 +84,48 @@ When \f[C]sqlite3\f[] is used, the database will be located at
77
84
  \f[C]gemstash.db\f[] within the directory specified by
78
85
  \f[C]:base_path\f[].
79
86
  The database will automatically be created when using \f[C]sqlite3\f[].
80
- When \f[C]postgres\f[] is used, the database to connect to must be
81
- specified in the \f[C]:db_url\f[] configuration key.
82
- The database must already be created when using \f[C]postgres\f[].
87
+ When \f[C]postgres\f[], \f[C]mysql\f[], or \f[C]mysql2\f[] is used, the
88
+ database to connect to must be specified in the \f[C]:db_url\f[]
89
+ configuration key.
90
+ The database must already be created when using anything other than
91
+ \f[C]sqlite3\f[].
83
92
  .SS DEFAULT VALUE
84
93
  .PP
85
94
  \f[C]sqlite3\f[]
86
95
  .SS VALID VALUES
87
96
  .PP
88
- \f[C]sqlite3\f[], \f[C]postgres\f[]
97
+ \f[C]sqlite3\f[], \f[C]postgres\f[], \f[C]mysql\f[], \f[C]mysql2\f[]
89
98
  .SH DB URL
90
99
  .PP
91
100
  \f[C]:db_url\f[]
92
101
  .PP
93
- Specifies the database to connect to when using \f[C]postgres\f[] for
94
- the \f[C]:db_adapter\f[].
95
- Only used when \f[C]postgres\f[] is used for \f[C]:db_adapter\f[].
102
+ Specifies the database to connect to when using \f[C]postgres\f[],
103
+ \f[C]mysql\f[], or \f[C]mysql2\f[] for the \f[C]:db_adapter\f[].
104
+ Only used when the \f[C]:db_adapter\f[] is not \f[C]sqlite3\f[].
96
105
  .SS DEFAULT VALUE
97
106
  .PP
98
107
  None
99
108
  .SS VALID VALUES
100
109
  .PP
101
110
  A valid database URL for the Sequel gem (http://sequel.jeremyevans.net/)
111
+ .SH DB CONNECTION OPTIONS
112
+ .PP
113
+ \f[C]:db_connection_options\f[]
114
+ .PP
115
+ Specifies additional \f[C]Sequel.connect\f[] options to use.
116
+ Note that any options here are merged in with the default options, so
117
+ you need not specify the \f[C]max_connections\f[] if you customize this
118
+ option.
119
+ .SS DEFAULT VALUE
120
+ .PP
121
+ \f[C]{\ max_connections:\ 1\ }\f[] for \f[C]sqlite3\f[] adapter,
122
+ \f[C]{\ max_connections:\ config[:puma_threads]\ +\ 1\ }\f[] for any
123
+ other adapter.
124
+ .SS VALID VALUES
125
+ .PP
126
+ A valid connection options Hash for the
127
+ Sequel.connect (http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html#label-General+connection+options)
128
+ method.
102
129
  .SH RUBYGEMS URL
103
130
  .PP
104
131
  \f[C]:rubygems_url\f[]
@@ -115,6 +142,17 @@ for the previous value.
115
142
  .SS VALID VALUES
116
143
  .PP
117
144
  A valid gem source URL
145
+ .SH PUMA THREADS
146
+ .PP
147
+ \f[C]:puma_threads\f[]
148
+ .PP
149
+ Specifies the number of threads used for the Gemstash server.
150
+ .SS DEFAULT VALUE
151
+ .PP
152
+ \f[C]16\f[]
153
+ .SS VALID VALUES
154
+ .PP
155
+ Integer value with a minimum of \f[C]1\f[]
118
156
  .SH BIND ADDRESS
119
157
  .PP
120
158
  \f[C]:bind\f[]
@@ -131,3 +169,47 @@ as the root user.
131
169
  .PP
132
170
  Any valid binding that is supported by
133
171
  Puma (https://github.com/puma/puma#binding-tcp--sockets)
172
+ .SH PROTECTED FETCH
173
+ .PP
174
+ \f[C]:protected_fetch\f[]
175
+ .PP
176
+ Tells Gemstash to authenticate via an API key before allowing the
177
+ fetching of private gems and specs.
178
+ The default behavior is to allow unauthenticated download of private
179
+ gems and specs.
180
+ .SS DEFAULT VALUE
181
+ .PP
182
+ \f[C]false\f[]
183
+ .SS VALID VALUES
184
+ .PP
185
+ Boolean values \f[C]true\f[] or \f[C]false\f[]
186
+ .SH FETCH TIMEOUT
187
+ .PP
188
+ \f[C]:fetch_timeout\f[]
189
+ .PP
190
+ The timeout setting for fetching gems.
191
+ Fetching gems over a slow connection may cause timeout errors.
192
+ If you experience timeout errors, you may want to increase this value.
193
+ The default is \f[C]20\f[] seconds.
194
+ .SS DEFAULT VALUE
195
+ .PP
196
+ \f[C]20\f[]
197
+ .SS VALID VALUES
198
+ .PP
199
+ Integer value with a minimum of \f[C]1\f[]
200
+ .SH LOG FILE
201
+ .PP
202
+ \f[C]:log_file\f[]
203
+ .PP
204
+ Indicates the name of the file to use for logging.
205
+ The file will be placed in the base
206
+ path (gemstash help configuration.5).
207
+ .SS DEFAULT VALUE
208
+ .PP
209
+ \f[C]server.log\f[]
210
+ .SS VALID VALUES
211
+ .PP
212
+ Any valid file name, or \f[C]:stdout\f[] to log to \f[C]$stdout\f[]
213
+ .PP
214
+ \f[I]Note: Using \f[C]:stdout\f[] for the \f[C]:log_file\f[] requires
215
+ running with \f[C]\-\-no\-daemonize\f[] (gemstash help start.1).\f[]