- stderr and null drivers; per-component levels from log.components - SUMMER_LOG__ overrides parse as strings and overlay the defaults key by key - Validation names the key: driver, format, level, days, stack children and cycles, daily path outside the root - summer new writes config/log.yaml (stack of console and daily, river warn, http info) - docs/services/logging.md: channels, config/log.yaml, component loggers, daily files, redaction - Log keys in the configuration docs; ExampleFor backs the docs snippet
4.7 KiB
title, description, section, order
| title | description | section | order |
|---|---|---|---|
| Configuration | Read layered configuration with compass, from plugin defaults through per-environment files and SUMMER_ variables to runtime overrides saved to disk. | services | 10 |
Configuration
WinterCMS reads configuration with Config::get('app.name') from config/*.php, per-environment directories and .env. SummerCMS reads it from a compass.Config built by compass, with the same dot paths. Setup, Configuration lists the keys an application sets; this page covers how the layers merge and how code reads and changes them.
Layers
compass.Config merges its sources in a fixed order. Each layer overrides the ones before it:
- Plugin defaults, merged with
compass.Config.MergePluginwhen the plugin is activated. A plugin'sconfig/config.yamlbecomes<plugin id>.<key>, soacme.blog.posts_per_pageis the WinterCMSacme.blog::posts_per_page. Any otherconfig/<name>.yamlbecomes<plugin id>.<name>.<key>. config/*.yaml. Each file is a section named after the file, soconfig/app.yamlprovidesapp.*.config/env/<environment>/*.yaml, the per-environment sections.SUMMER_environment variables and the.envfile next toconfig/.SUMMER_MAIL__DRIVERsetsmail.driver: the prefix is removed,__separates the path segments and the name is lower-cased. A.envvalue applies only when the real environment does not set the same variable. Values arrive as strings; modules that expect numbers or lists either parse them (SUMMER_LOG__CHANNELS__DAILY__DAYS=30andSUMMER_LOG__CHANNELS__STACK__CHANNELS=console,dailywork for the logging keys) or document that the key belongs in YAML.config/env/<environment>/overrides.yaml, written bycompass.Config.Persist.- Values set in memory with
compass.Config.Set.
The environment comes from SUMMER_ENV and defaults to production. Its name may contain only letters, digits, - and _.
Reading values
The typed getters compass.Config.String, compass.Config.Int and compass.Config.Bool return the zero value for a missing key. Use compass.Config.Lookup or compass.Config.Has when a missing key must be told apart from a zero value, and compass.Config.LoadSection to read a whole section into a struct with koanf tags:
dir, err := os.MkdirTemp("", "acme-config")
if err != nil {
fmt.Println(err)
return
}
defer os.RemoveAll(dir)
if err := writeConfig(dir); err != nil {
fmt.Println(err)
return
}
// Environ stands in for the process environment (nil reads os.Environ).
cfg, err := compass.Open(compass.Options{
Dir: dir,
Env: "development",
Environ: []string{"SUMMER_MAIL__DRIVER=smtp"},
})
if err != nil {
fmt.Println(err)
return
}
// A plugin's embedded config/config.yaml becomes its defaults.
plugin := fstest.MapFS{"config/config.yaml": {Data: []byte("posts_per_page: 10\n")}}
if err := cfg.MergePlugin("acme.blog", plugin); err != nil {
fmt.Println(err)
return
}
fmt.Println(cfg.String("app.name"), cfg.Bool("app.debug"), cfg.Int("acme.blog.posts_per_page"))
var mail mailSettings
if err := cfg.LoadSection("mail", &mail); err != nil {
fmt.Println(err)
return
}
fmt.Println(mail.Driver, mail.From)
_, found := cfg.Lookup("app.timezone")
fmt.Println(cfg.Environment(), found)
// A runtime override, saved to env/development/overrides.yaml.
if err := cfg.Set("acme.blog.posts_per_page", 25); err != nil {
fmt.Println(err)
return
}
if err := cfg.Persist(); err != nil {
fmt.Println(err)
return
}
saved, _ := os.ReadFile(filepath.Join(dir, "env", "development", "overrides.yaml"))
fmt.Print(string(saved))
// Output:
// Acme true 10
// smtp blog@example.com
// development false
// acme:
// blog:
// posts_per_page: 25
The application opens its configuration once with compass.Load("config") in the generated main and hands it to the backpack.App. Plugins read it through app.Config and never open their own.
Changing values at runtime
compass.Config.Set changes a value in memory. compass.Config.Persist saves every value set at runtime to config/env/<environment>/overrides.yaml, keeping the keys already saved there. It replaces the file atomically, creates it readable only by its owner and refuses any path outside the config directory. compass.Config.Reload rereads every source and discards values that were set but not persisted.
Values that admins edit in the backend are not configuration: settings pages store them in a database row; see Settings.
Warning
overrides.yamlis written by the running application. Keep it out of version control, and keep secrets in environment variables rather than in values the application persists.