github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/config/config.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package config 18 19 import ( 20 "context" 21 "fmt" 22 "net/http" 23 "os" 24 "sort" 25 "strings" 26 "time" 27 28 "github.com/kaleido-io/firefly/internal/i18n" 29 "github.com/kaleido-io/firefly/internal/log" 30 "github.com/kaleido-io/firefly/pkg/fftypes" 31 "github.com/sirupsen/logrus" 32 "github.com/spf13/viper" 33 ) 34 35 // The following keys can be access from the root configuration. 36 // Plugins are resonsible for defining their own keys using the Config interface 37 var ( 38 // APIDefaultFilterLimit is the default limit that will be applied to filtered queries on the API 39 APIDefaultFilterLimit = rootKey("api.defaultFilterLimit") 40 // APIMaxFilterLimit is the maximum limit that can be specified by an API call 41 APIMaxFilterLimit = rootKey("api.maxFilterLimit") 42 // APIMaxFilterSkip is the maximum skip value that can be specified on the API 43 APIMaxFilterSkip = rootKey("api.maxFilterLimit") 44 // APIRequestTimeout is the server side timeout for API calls (context timeout), to avoid the server continuing processing when the client gives up 45 APIRequestTimeout = rootKey("api.requestTimeout") 46 // BatchManagerReadPageSize is the size of each page of messages read from the database into memory when assembling batches 47 BatchManagerReadPageSize = rootKey("batch.manager.readPageSize") 48 // BatchManagerReadPollTimeout is how long without any notifications of new messages to wait, before doing a page query 49 BatchManagerReadPollTimeout = rootKey("batch.manager.pollTimeout") 50 // BatchRetryFactor is the retry backoff factor for database operations performed by the batch manager 51 BatchRetryFactor = rootKey("batch.retry.factor") 52 // BatchRetryInitDelay is the retry initial delay for database operations 53 BatchRetryInitDelay = rootKey("batch.retry.initDelay") 54 // BatchRetryMaxDelay is the maximum delay between retry attempts 55 BatchRetryMaxDelay = rootKey("batch.retry.maxDelay") 56 // BlockchainType is the name of the blockchain interface plugin being used by this firefly name 57 BlockchainType = rootKey("blockchain.type") 58 // BroadcastBatchAgentTimeout how long to keep around a batching agent for a sending identity before disposal 59 BroadcastBatchAgentTimeout = rootKey("broadcast.batch.agentTimeout") 60 // BroadcastBatchSize is the maximum size of a batch for broadcast messages 61 BroadcastBatchSize = rootKey("broadcast.batch.size") 62 // BroadcastBatchTimeout is the timeout to wait for a batch to fill, before sending 63 BroadcastBatchTimeout = rootKey("broadcast.batch.timeout") 64 // PrivateMessagingBatchAgentTimeout how long to keep around a batching agent for a sending identity before disposal 65 PrivateMessagingBatchAgentTimeout = rootKey("privatemessaging.batch.agentTimeout") 66 // PrivateMessagingBatchSize is the maximum size of a batch for broadcast messages 67 PrivateMessagingBatchSize = rootKey("privatemessaging.batch.size") 68 // PrivateMessagingBatchTimeout is the timeout to wait for a batch to fill, before sending 69 PrivateMessagingBatchTimeout = rootKey("privatemessaging.batch.timeout") 70 // PrivateMessagingOpCorrelationRetries how many times to correlate an event for an operation (such as tx submission) back to an operation. 71 // Needed because the operation update might come back before we are finished persisting the ID of the request 72 PrivateMessagingOpCorrelationRetries = rootKey("privatemessaging.opCorrelationRetries") 73 // PrivateMessagingRetryFactor the backoff factor to use for retry of database operations 74 PrivateMessagingRetryFactor = rootKey("privatemessaging.retry.factor") 75 // PrivateMessagingRetryInitDelay the initial delay to use for retry of data base operations 76 PrivateMessagingRetryInitDelay = rootKey("privatemessaging.retry.initDelay") 77 // PrivateMessagingRetryMaxDelay the maximum delay to use for retry of data base operations 78 PrivateMessagingRetryMaxDelay = rootKey("privatemessaging.retry.maxDelay") 79 // CorsAllowCredentials CORS setting to control whether a browser allows credentials to be sent to this API 80 CorsAllowCredentials = rootKey("cors.credentials") 81 // CorsAllowedHeaders CORS setting to control the allowed headers 82 CorsAllowedHeaders = rootKey("cors.headers") 83 // CorsAllowedMethods CORS setting to control the allowed methods 84 CorsAllowedMethods = rootKey("cors.methods") 85 // CorsAllowedOrigins CORS setting to control the allowed origins 86 CorsAllowedOrigins = rootKey("cors.origins") 87 // CorsDebug is whether debug is enabled for the CORS implementation 88 CorsDebug = rootKey("cors.debug") 89 // CorsEnabled is whether cors is enabled 90 CorsEnabled = rootKey("cors.enabled") 91 // CorsMaxAge is the maximum age a browser should rely on CORS checks 92 CorsMaxAge = rootKey("cors.maxAge") 93 // DataexchangeType is the name of the data exchange plugin being used by this firefly name 94 DataexchangeType = rootKey("dataexchange.type") 95 // DatabaseType the type of the database interface plugin to use 96 DatabaseType = rootKey("database.type") 97 // DebugPort a HTTP port on which to enable the go debugger 98 DebugPort = rootKey("debug.port") 99 // EventTransportsDefault the default event transport for new subscriptions 100 EventTransportsDefault = rootKey("event.transports.default") 101 // EventTransportsEnabled which event interface plugins are enabled 102 EventTransportsEnabled = rootKey("event.transports.enabled") 103 // EventAggregatorFirstEvent the first event the aggregator should process, if no previous offest is stored in the DB 104 EventAggregatorFirstEvent = rootKey("event.aggregator.firstEvent") 105 // EventAggregatorBatchSize the maximum number of records to read from the DB before performing an aggregation run 106 EventAggregatorBatchSize = rootKey("event.aggregator.batchSize") 107 // EventAggregatorBatchTimeout how long to wait for new events to arrive before performing aggregation on a page of events 108 EventAggregatorBatchTimeout = rootKey("event.aggregator.batchTimeout") 109 // EventAggregatorOpCorrelationRetries how many times to correlate an event for an operation (such as tx submission) back to an operation. 110 // Needed because the operation update might come back before we are finished persisting the ID of the request 111 EventAggregatorOpCorrelationRetries = rootKey("event.aggregator.opCorrelationRetries") 112 // EventAggregatorPollTimeout the time to wait without a notification of new events, before trying a select on the table 113 EventAggregatorPollTimeout = rootKey("event.aggregator.pollTimeout") 114 // EventAggregatorRetryFactor the backoff factor to use for retry of database operations 115 EventAggregatorRetryFactor = rootKey("event.aggregator.retry.factor") 116 // EventAggregatorRetryInitDelay the initial delay to use for retry of data base operations 117 EventAggregatorRetryInitDelay = rootKey("event.aggregator.retry.initDelay") 118 // EventAggregatorRetryMaxDelay the maximum delay to use for retry of data base operations 119 EventAggregatorRetryMaxDelay = rootKey("event.aggregator.retry.maxDelay") 120 // EventDispatcherPollTimeout the time to wait without a notification of new events, before trying a select on the table 121 EventDispatcherPollTimeout = rootKey("event.dispatcher.pollTimeout") 122 // EventDispatcherBufferLength the number of events + attachments an individual dispatcher should hold in memory ready for delivery to the subscription 123 EventDispatcherBufferLength = rootKey("event.dispatcher.bufferLength") 124 // EventDispatcherBatchTimeout a short time to wait for new events to arrive before re-polling for new events 125 EventDispatcherBatchTimeout = rootKey("event.dispatcher.batchTimeout") 126 // EventDispatcherRetryFactor the backoff factor to use for retry of database operations 127 EventDispatcherRetryFactor = rootKey("event.dispatcher.retry.factor") 128 // EventDispatcherRetryInitDelay he initial delay to use for retry of data base operations 129 EventDispatcherRetryInitDelay = rootKey("event.dispatcher.retry.initDelay") 130 // EventDispatcherRetryMaxDelay he maximum delay to use for retry of data base operations 131 EventDispatcherRetryMaxDelay = rootKey("event.dispatcher.retry.maxDelay") 132 // GroupCacheSize cache size for private group addresses 133 GroupCacheSize = rootKey("group.cache.size") 134 // GroupCacheTTL cache time-to-live for private group addresses 135 GroupCacheTTL = rootKey("group.cache.ttl") 136 // HttpAddress the local address to listen on for HTTP/Websocket connections (empty means any address) 137 HTTPAddress = rootKey("http.address") 138 // HttpPort the local port to listen on for HTTP/Websocket connections 139 HTTPPort = rootKey("http.port") 140 // HttpReadTimeout the write timeout for the HTTP server 141 HTTPReadTimeout = rootKey("http.readTimeout") 142 // HttpTLSCAFile the TLS certificate authority file for the HTTP server 143 HTTPTLSCAFile = rootKey("http.tls.caFile") 144 // HttpTLSCertFile the TLS certificate file for the HTTP server 145 HTTPTLSCertFile = rootKey("http.tls.certFile") 146 // HttpTLSClientAuth whether the HTTP server requires a mutual TLS connection 147 HTTPTLSClientAuth = rootKey("http.tls.clientAuth") 148 // HttpTLSEnabled whether TLS is enabled for the HTTP server 149 HTTPTLSEnabled = rootKey("http.tls.enabled") 150 // HttpTLSKeyFile the private key file for TLS on the server 151 HTTPTLSKeyFile = rootKey("http.tls.keyFile") 152 // HttpWriteTimeout the write timeout for the HTTP server 153 HTTPWriteTimeout = rootKey("http.writeTimeout") 154 // IdentityType is the name of the inentity interface plugin being used by this firefly name 155 IdentityType = rootKey("identity.type") 156 // Lang is the language to use for translation 157 Lang = rootKey("lang") 158 // LogForceColor forces color to be enabled, even if we do not detect a TTY 159 LogForceColor = rootKey("log.forceColor") 160 // LogLevel is the logging level 161 LogLevel = rootKey("log.level") 162 // LogNoColor forces color to be disabled, even if we detect a TTY 163 LogNoColor = rootKey("log.noColor") 164 // LogTimeFormat is a string format for timestamps 165 LogTimeFormat = rootKey("log.timeFormat") 166 // LogUTC sets log timestamps to the UTC timezone 167 LogUTC = rootKey("log.utc") 168 // NamespacesDefault is the default namespace - must be in the predefines list 169 NamespacesDefault = rootKey("namespaces.default") 170 // NamespacesPredefined is a list of namespaces to ensure exists, without requiring a broadcast from the network 171 NamespacesPredefined = rootKey("namespaces.predefined") 172 // NodeName is a description for the node 173 NodeName = rootKey("node.name") 174 // NodeDescription is a description for the node 175 NodeDescription = rootKey("node.description") 176 // OrgName is the short name o the org 177 OrgName = rootKey("org.name") 178 // OrgIdentity is the signing identity allocated to the organization (can be the same as the nodes) 179 OrgIdentity = rootKey("org.identity") 180 // OrgDescription is a description for the org 181 OrgDescription = rootKey("org.description") 182 // OrchestratorStartupAttempts is how many time to attempt to connect to core infrastructure on startup 183 OrchestratorStartupAttempts = rootKey("orchestrator.startupAttempts") 184 // PublicStorageType specifies which public storage interface plugin to use 185 PublicStorageType = rootKey("publicstorage.type") 186 // SubscriptionDefaultsReadAhead default read ahead to enable for subscriptions that do not explicitly configure readahead 187 SubscriptionDefaultsReadAhead = rootKey("subscription.defaults.batchSize") 188 // SubscriptionMax maximum number of pre-defined subscriptions that can exist (note for high fan-out consider connecting a dedicated pub/sub broker to the dispatcher) 189 SubscriptionMax = rootKey("subscription.max") 190 // SubscriptionsRetryInitialDelay is the initial retry delay 191 SubscriptionsRetryInitialDelay = rootKey("subscription.retry.initDelay") 192 // SubscriptionsRetryMaxDelay is the initial retry delay 193 SubscriptionsRetryMaxDelay = rootKey("subscription.retry.maxDelay") 194 // SubscriptionsRetryFactor the backoff factor to use for retry of database operations 195 SubscriptionsRetryFactor = rootKey("event.dispatcher.retry.factor") 196 // UIPath the path on which to serve the UI 197 UIPath = rootKey("ui.path") 198 // ValidatorCacheSize 199 ValidatorCacheSize = rootKey("validator.cache.size") 200 // ValidatorCacheTTL 201 ValidatorCacheTTL = rootKey("validator.cache.ttl") 202 ) 203 204 // Prefix represents the global configuration, at a nested point in 205 // the config hierarchy. This allows plugins to define their 206 // Note that all values are GLOBAL so this cannot be used for per-instance 207 // customization. Rather for global initialization of plugins. 208 type Prefix interface { 209 AddKnownKey(key string, defValue ...interface{}) 210 SubPrefix(suffix string) Prefix 211 Set(key string, value interface{}) 212 Resolve(key string) string 213 214 GetString(key string) string 215 GetBool(key string) bool 216 GetInt(key string) int 217 GetInt64(key string) int64 218 GetByteSize(key string) int64 219 GetUint(key string) uint 220 GetDuration(key string) time.Duration 221 GetStringSlice(key string) []string 222 GetObject(key string) fftypes.JSONObject 223 GetObjectArray(key string) fftypes.JSONObjectArray 224 Get(key string) interface{} 225 } 226 227 // RootKey key are the known configuration keys 228 type RootKey string 229 230 func Reset() { 231 viper.Reset() 232 233 // Set defaults 234 viper.SetDefault(string(APIDefaultFilterLimit), 25) 235 viper.SetDefault(string(APIRequestTimeout), "120s") 236 viper.SetDefault(string(APIMaxFilterLimit), 250) 237 viper.SetDefault(string(APIMaxFilterSkip), 1000) // protects database (skip+limit pagination is not for bulk operations) 238 viper.SetDefault(string(APIRequestTimeout), "120s") 239 viper.SetDefault(string(BatchManagerReadPageSize), 100) 240 viper.SetDefault(string(BatchManagerReadPollTimeout), "30s") 241 viper.SetDefault(string(BatchRetryFactor), 2.0) 242 viper.SetDefault(string(BatchRetryFactor), 2.0) 243 viper.SetDefault(string(BatchRetryInitDelay), "250ms") 244 viper.SetDefault(string(BatchRetryInitDelay), "250ms") 245 viper.SetDefault(string(BatchRetryMaxDelay), "30s") 246 viper.SetDefault(string(BatchRetryMaxDelay), "30s") 247 viper.SetDefault(string(BroadcastBatchAgentTimeout), "2m") 248 viper.SetDefault(string(BroadcastBatchSize), 200) 249 viper.SetDefault(string(BroadcastBatchTimeout), "1s") 250 viper.SetDefault(string(CorsAllowCredentials), true) 251 viper.SetDefault(string(CorsAllowedHeaders), []string{"*"}) 252 viper.SetDefault(string(CorsAllowedMethods), []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete}) 253 viper.SetDefault(string(CorsAllowedOrigins), []string{"*"}) 254 viper.SetDefault(string(CorsEnabled), true) 255 viper.SetDefault(string(CorsMaxAge), 600) 256 viper.SetDefault(string(DataexchangeType), "https") 257 viper.SetDefault(string(DebugPort), -1) 258 viper.SetDefault(string(EventAggregatorFirstEvent), fftypes.SubOptsFirstEventOldest) 259 viper.SetDefault(string(EventAggregatorBatchSize), 50) 260 viper.SetDefault(string(EventAggregatorBatchTimeout), "250ms") 261 viper.SetDefault(string(EventAggregatorPollTimeout), "30s") 262 viper.SetDefault(string(EventAggregatorRetryFactor), 2.0) 263 viper.SetDefault(string(EventAggregatorRetryInitDelay), "100ms") 264 viper.SetDefault(string(EventAggregatorRetryMaxDelay), "30s") 265 viper.SetDefault(string(EventAggregatorOpCorrelationRetries), 3) 266 viper.SetDefault(string(EventDispatcherBufferLength), 5) 267 viper.SetDefault(string(EventDispatcherBatchTimeout), "250ms") 268 viper.SetDefault(string(EventDispatcherPollTimeout), "30s") 269 viper.SetDefault(string(EventTransportsEnabled), []string{"websockets"}) 270 viper.SetDefault(string(EventTransportsDefault), "websockets") 271 viper.SetDefault(string(GroupCacheSize), "1Mb") 272 viper.SetDefault(string(GroupCacheTTL), "1h") 273 viper.SetDefault(string(HTTPAddress), "127.0.0.1") 274 viper.SetDefault(string(HTTPPort), 5000) 275 viper.SetDefault(string(HTTPReadTimeout), "15s") 276 viper.SetDefault(string(HTTPWriteTimeout), "15s") 277 viper.SetDefault(string(IdentityType), "onchain") 278 viper.SetDefault(string(Lang), "en") 279 viper.SetDefault(string(LogLevel), "info") 280 viper.SetDefault(string(LogTimeFormat), "2006-01-02T15:04:05.000Z07:00") 281 viper.SetDefault(string(LogUTC), false) 282 viper.SetDefault(string(NamespacesDefault), "default") 283 viper.SetDefault(string(NamespacesPredefined), fftypes.JSONObjectArray{{"name": "default", "description": "Default predefined namespace"}}) 284 viper.SetDefault(string(OrchestratorStartupAttempts), 5) 285 viper.SetDefault(string(PrivateMessagingRetryFactor), 2.0) 286 viper.SetDefault(string(PrivateMessagingRetryInitDelay), "100ms") 287 viper.SetDefault(string(PrivateMessagingRetryMaxDelay), "30s") 288 viper.SetDefault(string(PrivateMessagingOpCorrelationRetries), 3) 289 viper.SetDefault(string(PrivateMessagingBatchAgentTimeout), "2m") 290 viper.SetDefault(string(PrivateMessagingBatchSize), 200) 291 viper.SetDefault(string(PrivateMessagingBatchTimeout), "1s") 292 viper.SetDefault(string(SubscriptionDefaultsReadAhead), 0) 293 viper.SetDefault(string(SubscriptionMax), 500) 294 viper.SetDefault(string(SubscriptionsRetryInitialDelay), "250ms") 295 viper.SetDefault(string(SubscriptionsRetryMaxDelay), "30s") 296 viper.SetDefault(string(SubscriptionsRetryFactor), 2.0) 297 viper.SetDefault(string(ValidatorCacheSize), "1Mb") 298 viper.SetDefault(string(ValidatorCacheTTL), "1h") 299 300 i18n.SetLang(GetString(Lang)) 301 } 302 303 // ReadConfig initializes the config 304 func ReadConfig(cfgFile string) error { 305 Reset() 306 307 // Set precedence order for reading config location 308 viper.SetEnvPrefix("firefly") 309 viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) 310 viper.AutomaticEnv() 311 viper.SetConfigType("yaml") 312 if cfgFile != "" { 313 f, err := os.Open(cfgFile) 314 if err == nil { 315 defer f.Close() 316 err = viper.ReadConfig(f) 317 } 318 return err 319 } 320 viper.SetConfigName("firefly.core") 321 viper.AddConfigPath("/etc/firefly/") 322 viper.AddConfigPath("$HOME/.firefly") 323 viper.AddConfigPath(".") 324 return viper.ReadInConfig() 325 } 326 327 var root = &configPrefix{ 328 keys: map[string]bool{}, // All keys go here, including those defined in sub prefixies 329 } 330 331 // ark adds a root key, used to define the keys that are used within the core 332 func rootKey(k string) RootKey { 333 root.AddKnownKey(k) 334 return RootKey(k) 335 } 336 337 // GetKnownKeys gets the known keys 338 func GetKnownKeys() []string { 339 var keys []string 340 for k := range root.keys { 341 keys = append(keys, k) 342 } 343 sort.Strings(keys) 344 return keys 345 } 346 347 // configPrefix is the main config structure passed to plugins, and used for root to wrap viper 348 type configPrefix struct { 349 prefix string 350 keys map[string]bool 351 } 352 353 // NewPluginConfig creates a new plugin configuration object, at the specified prefix 354 func NewPluginConfig(prefix string) Prefix { 355 if !strings.HasSuffix(prefix, ".") { 356 prefix += "." 357 } 358 return &configPrefix{ 359 prefix: prefix, 360 keys: root.keys, 361 } 362 } 363 364 func (c *configPrefix) prefixKey(k string) string { 365 key := c.prefix + k 366 if !c.keys[key] { 367 panic(fmt.Sprintf("Undefined configuration key '%s'", key)) 368 } 369 return key 370 } 371 372 func (c *configPrefix) SubPrefix(suffix string) Prefix { 373 return &configPrefix{ 374 prefix: c.prefix + suffix + ".", 375 keys: root.keys, 376 } 377 } 378 379 func (c *configPrefix) AddKnownKey(k string, defValue ...interface{}) { 380 key := c.prefix + k 381 if len(defValue) == 1 { 382 viper.SetDefault(key, defValue[0]) 383 } else if len(defValue) > 0 { 384 viper.SetDefault(key, defValue) 385 } 386 c.keys[key] = true 387 } 388 389 // GetString gets a configuration string 390 func GetString(key RootKey) string { 391 return root.GetString(string(key)) 392 } 393 func (c *configPrefix) GetString(key string) string { 394 return viper.GetString(c.prefixKey(key)) 395 } 396 397 // GetStringSlice gets a configuration string array 398 func GetStringSlice(key RootKey) []string { 399 return root.GetStringSlice(string(key)) 400 } 401 func (c *configPrefix) GetStringSlice(key string) []string { 402 return viper.GetStringSlice(c.prefixKey(key)) 403 } 404 405 // GetBool gets a configuration bool 406 func GetBool(key RootKey) bool { 407 return root.GetBool(string(key)) 408 } 409 func (c *configPrefix) GetBool(key string) bool { 410 return viper.GetBool(c.prefixKey(key)) 411 } 412 413 // GetDuration gets a configuration time duration with consistent semantics 414 func GetDuration(key RootKey) time.Duration { 415 return root.GetDuration(string(key)) 416 } 417 func (c *configPrefix) GetDuration(key string) time.Duration { 418 return fftypes.ParseToDuration(viper.GetString(c.prefixKey(key))) 419 } 420 421 // GetByteSize get a size in bytes 422 func GetByteSize(key RootKey) int64 { 423 return root.GetByteSize(string(key)) 424 } 425 func (c *configPrefix) GetByteSize(key string) int64 { 426 return fftypes.ParseToByteSize(c.GetString(key)) 427 } 428 429 // GetUint gets a configuration uint 430 func GetUint(key RootKey) uint { 431 return root.GetUint(string(key)) 432 } 433 func (c *configPrefix) GetUint(key string) uint { 434 return viper.GetUint(c.prefixKey(key)) 435 } 436 437 // GetInt gets a configuration uint 438 func GetInt(key RootKey) int { 439 return root.GetInt(string(key)) 440 } 441 func (c *configPrefix) GetInt(key string) int { 442 return viper.GetInt(c.prefixKey(key)) 443 } 444 445 // GetInt64 gets a configuration uint 446 func GetInt64(key RootKey) int64 { 447 return root.GetInt64(string(key)) 448 } 449 func (c *configPrefix) GetInt64(key string) int64 { 450 return viper.GetInt64(c.prefixKey(key)) 451 } 452 453 // GetFloat64 gets a configuration uint 454 func GetFloat64(key RootKey) float64 { 455 return root.GetFloat64(string(key)) 456 } 457 func (c *configPrefix) GetFloat64(key string) float64 { 458 return viper.GetFloat64(c.prefixKey(key)) 459 } 460 461 // GetObject gets a configuration map 462 func GetObject(key RootKey) fftypes.JSONObject { 463 return root.GetObject(string(key)) 464 } 465 func (c *configPrefix) GetObject(key string) fftypes.JSONObject { 466 return fftypes.JSONObject(viper.GetStringMap(c.prefixKey(key))) 467 } 468 469 // GetObjectArray gets an array of configuration maps 470 func GetObjectArray(key RootKey) fftypes.JSONObjectArray { 471 return root.GetObjectArray(string(key)) 472 } 473 func (c *configPrefix) GetObjectArray(key string) fftypes.JSONObjectArray { 474 v, _ := fftypes.ToJSONObjectArray(viper.Get(c.prefixKey(key))) 475 return v 476 } 477 478 // Get gets a configuration in raw form 479 func Get(key RootKey) interface{} { 480 return root.Get(string(key)) 481 } 482 func (c *configPrefix) Get(key string) interface{} { 483 return viper.Get(c.prefixKey(key)) 484 } 485 486 // Set allows runtime setting of config (used in unit tests) 487 func Set(key RootKey, value interface{}) { 488 root.Set(string(key), value) 489 } 490 func (c *configPrefix) Set(key string, value interface{}) { 491 viper.Set(c.prefixKey(key), value) 492 } 493 494 // Resolve gives the fully qualified path of a key 495 func (c *configPrefix) Resolve(key string) string { 496 return c.prefixKey(key) 497 } 498 499 // SetupLogging initializes logging 500 func SetupLogging(ctx context.Context) { 501 log.SetFormatting(log.Formatting{ 502 DisableColor: GetBool(LogNoColor), 503 ForceColor: GetBool(LogForceColor), 504 TimestampFormat: GetString(LogTimeFormat), 505 UTC: GetBool(LogUTC), 506 }) 507 log.SetLevel(GetString(LogLevel)) 508 log.L(ctx).Debugf("Log level: %s", logrus.GetLevel()) 509 }