Як поводитися з конфігурацією в Go [closed]


284

Я новачок у програмуванні Go, і мені цікаво: що є кращим способом обробки параметрів конфігурації для програми Go (вид речі, для якого можна використовувати файли властивостей або ini- файли, в інших контекстах)?


Я також почав нитку голанг-горіхів, яка має кілька додаткових ідей.
theglauber

2
Я схильний використовувати сценарії оболонки та змінні середовища.
праворуч

3
Я присвятив цілу публікацію в блозі Постійна конфігурація програми In Go, де я пояснив, як це зробити з прикладами для двох найпопулярніших форматів: json та YAML. Приклади готові до виробництва.
запиту

Тільки для запису є HCL від HashiCorp, який підтримує коментарі та сумісний з JSON та UCL. github.com/hashicorp/hcl
Каве Shahbazian

Відповіді:


244

Формат JSON працював для мене досить добре. Стандартна бібліотека пропонує способи запису структури даних у відступі, тому вона досить читабельна.

Дивіться також цю нитку голанг-горіхів .

Переваги JSON полягають у тому, що він досить просто розбирає та читає / редагує людину / редагує, пропонуючи семантику для списків та відображень (що може стати досить зручним), що не стосується багатьох конфігураційних парсерів ini-типу.

Приклад використання:

conf.json :

{
    "Users": ["UserA","UserB"],
    "Groups": ["GroupA"]
}

Програма для зчитування конфігурації

import (
    "encoding/json"
    "os"
    "fmt"
)

type Configuration struct {
    Users    []string
    Groups   []string
}

file, _ := os.Open("conf.json")
defer file.Close()
decoder := json.NewDecoder(file)
configuration := Configuration{}
err := decoder.Decode(&configuration)
if err != nil {
  fmt.Println("error:", err)
}
fmt.Println(configuration.Users) // output: [UserA, UserB]

6
Здається, що JSON - найменш поганий з нинішніх альтернатив. Я переглянув go-yaml, і це зухвале зусилля, але я брав відсутність документації як ознаку того, що мені слід шукати в іншому місці. Гоніні, здається, є простою та легкою бібліотекою для обробки ini- файлів Windows . Запропоновано новий формат під назвою TOML, але він також має проблеми . У цей момент я б дотримувався JSON або ini .
theglauber

6
YAML підтримує коментарі, якщо ви хочете додавати примітки скрізь у конфігураційний файл.
Іван Чорний

42
Для тих, хто читає це та йде по цьому маршруту, будьте обережні: відсутність коментарів JSON робить його непридатним для користувальницького файлу конфігурації (imo). Це формат обміну даними - ви можете втратити можливість писати корисні / описові коментарі у конфігураційні файли, які можуть зашкодити ремонтопридатності ("чому цей параметр активований?", "Що це робить?", "Які для нього є дійсними значеннями" ? "тощо).
Даріан Муді

6
А-а-а - я спробував це у своєму коді і забув визначити атрибути структури з великими літерами (не експортовані) - це коштувало мені години мого життя. Можливо, інші допустять ту саму помилку> попередити; D
JohnGalt

6
Ймовірно, варто defer file.Close()після перевірки відкритої помилки
Габріель,

97

Інший варіант - використовувати TOML , який є INI-подібним форматом, створеним Томом Престоном-Вернером. Я створив для нього аналізатор Go, який проходить випробування . Ви можете використовувати його, як і інші варіанти, запропоновані тут. Наприклад, якщо у вас є ці дані TOMLsomething.toml

Age = 198
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

Потім ви можете завантажити його у свою програму Go з чимось подібним

type Config struct {
    Age int
    Cats []string
    Pi float64
    Perfection []int
    DOB time.Time
}

var conf Config
if _, err := toml.DecodeFile("something.toml", &conf); err != nil {
    // handle error
}

18
Мені подобається TOML, тому що він дозволяє мені писати коментарі або в нових рядках, або в кінці рядка налаштування налаштування. Я не можу цього зробити з JSON.
сергсерг

Кожне оновлення конфігурації вимагає оновлення в коді, що дуже дратує.
hywak

4
Кожен підхід до налаштування робить. Як інакше ваша програма буде знати про нову конфігурацію?
BurntSushi5

@ BurntSushi5 Чи можуть бути додаткові поля у файлі Toml, про які код не піклується? Я маю на увазі, чи можна використовувати новішу версію конфігураційного файлу зі старшою версією коду? У моєму випадку це нормально ігнорувати невикористані параметри конфігурації.
користувач1952500

2
мені це подобається. Гарна робота. Особисто я думаю, що адміністраторам або клієнтам легше змінити файл TOML, ніж JSON.
blndev

49

Viper - це система управління конфігурацією golang, яка працює з JSON, YAML та TOML. Це виглядає досить цікаво.


1
Особливо життєздатний для 12факторних додатків 12factor.net
DerKnorr

Використовуйте gonfig для конфігурації JSON у Go. github.com/eduardbcom/gonfig
Едуард Бондаренко

1
Не використовуйте Viper, це не захист від ниток, який мене майже звільнив.
igonejack

@igonejack Наведіть приклад, де вас укусив Viper?
Dr.eel

1
@ Dr.eel Спробуйте окремі viper.GetBool ("abc") та Viper.Set ("abc", false) у різних програмах.
igonejack

44

Зазвичай я використовую JSON для складніших структур даних. Мінус полягає в тому, що ви легко отримуєте купу коду, щоб повідомити користувачеві, де була помилка, різні крайові випадки та що ні.

Що стосується базової конфігурації (ключі api, номери портів, ...), мені дуже вдало з пакетом gcfg . Він заснований на форматі git config.

З документації:

Приклад конфігурації:

; Comment line
[section]
name = value # Another comment
flag # implicit value for bool is true

Перехід:

type Config struct {
    Section struct {
            Name string
            Flag bool
    }
}

І код, необхідний для його читання:

var cfg Config
err := gcfg.ReadFileInto(&cfg, "myconfig.gcfg")

Він також підтримує значення зрізів, тому ви можете дозволити кілька разів вказувати ключ та інші приємні функції.


4
Оригінальний автор gcfg припинив проект та розпочав ще один пов'язаний sconf .
iwat

39

Просто використовуйте стандартні прапори Go with iniflags .

Стандартні прапори мають такі переваги:

  • Ідіоматичний.
  • Простий у використанні. Прапори можна легко додавати та розкидати по довільних пакетах, які використовує ваш проект.
  • У прапорів є позабірна підтримка значень та опису за замовчуванням.
  • Прапори забезпечують стандартний вихід "довідки" зі значеннями та описом за замовчуванням.

Єдиний стандарт недоліків стандартних ігор - це проблеми управління, коли кількість прапорів, які використовуються у вашій програмі, стає занадто великою.

Iniflags елегантно вирішує цю проблему: просто змініть два рядки в основному пакеті, і це магічним чином отримує підтримку для читання значень прапора з ini-файлу. Прапори з ini-файлів можна змінити, передавши нові значення в командному рядку.

Докладніше див. Також https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE .


Я почав використовувати прапори для проекту, над яким я працював (мій перший проект з нуля голанг), але мені цікаво, як поводитися з такими речами, як тести? Наприклад, це клієнт api, і я хотів би використовувати прапори, але, схоже, це надмірно ускладнить моє тестування ( go testне дає мені пропускати прапори), а конфігураційний файл не буде.
зачаян

встановити прапори з тестів легко:*FlagName = value
Стівен Сорока

9
Було б дуже корисно, якби тут був детальний приклад коду, який показує робочий приклад :)
zero_cool

Непогана ідея, коли вам потрібно поділитися конфігурацією з іншими програмами, написаними іншими мовами.
Кірзілла

запропонував би використовувати pflags замість прапорів. pflags використовує стандарт
позікс

12

Я почав використовувати Gcfg який використовує файли, подібні до Ini. Це просто - якщо ви хочете чогось простого, це хороший вибір.

Ось код завантаження, який я використовую зараз, має налаштування за замовчуванням і дозволяє прапорці командного рядка (не показано), які замінюють деякі мої конфігурації:

package util

import (
    "code.google.com/p/gcfg"
)

type Config struct {
    Port int
    Verbose bool
    AccessLog string
    ErrorLog string
    DbDriver string
    DbConnection string
    DbTblPrefix string
}

type configFile struct {
    Server Config
}

const defaultConfig = `
    [server]
    port = 8000
    verbose = false
    accessLog = -
    errorLog  = -
    dbDriver     = mysql
    dbConnection = testuser:TestPasswd9@/test
    dbTblPrefix  =
`

func LoadConfiguration(cfgFile string, port int, verbose bool) Config {
    var err error
    var cfg configFile

    if cfgFile != "" {
        err = gcfg.ReadFileInto(&cfg, cfgFile)
    } else {
        err = gcfg.ReadStringInto(&cfg, defaultConfig)
    }

    PanicOnError(err)

    if port != 0 {
        cfg.Server.Port = port
    }
    if verbose {
        cfg.Server.Verbose = true
    }

    return cfg.Server
}

2
Хіба це не саме те, про що вже говорилося?
немо

8

подивіться на gonfig

// load
config, _ := gonfig.FromJson(myJsonFile)
// read with defaults
host, _ := config.GetString("service/host", "localhost")
port, _ := config.GetInt("service/port", 80)
test, _ := config.GetBool("service/testing", false)
rate, _ := config.GetFloat("service/rate", 0.0)
// parse section into target structure
config.GetAs("service/template", &template)

Це добре, оскільки мені не доведеться переосмислювати всю конфігураційну структуру в
ході



5

Я написав просту бібліотеку ini config у голанг.

https://github.com/c4pt0r/cfg

безпечна програма, проста у використанні

package cfg
import (
    "testing"
)

func TestCfg(t *testing.T) {
    c := NewCfg("test.ini")
    if err := c.Load() ; err != nil {
        t.Error(err)
    }
    c.WriteInt("hello", 42)
    c.WriteString("hello1", "World")

    v, err := c.ReadInt("hello", 0)
    if err != nil || v != 42 {
        t.Error(err)
    }

    v1, err := c.ReadString("hello1", "")
    if err != nil || v1 != "World" {
        t.Error(err)
    }

    if err := c.Save(); err != nil {
        t.Error(err)
    }
}

=================== Оновити ========================

Нещодавно мені потрібен парсер INI з підтримкою розділу, і я пишу простий пакет:

github.com/c4pt0r/cfg

Ви можете проаналізувати INI, наприклад, використовуючи пакет "flag":

package main

import (
    "log"
    "github.com/c4pt0r/ini"
)

var conf = ini.NewConf("test.ini")

var (
    v1 = conf.String("section1", "field1", "v1")
    v2 = conf.Int("section1", "field2", 0)
)

func main() {
    conf.Parse()

    log.Println(*v1, *v2)
}

4

Можливо, вас також зацікавить go-libucl , набір зв'язків Go для UCL, універсальної мови конфігурації. UCL трохи схожий на JSON, але з кращою підтримкою для людей: він підтримує коментарі та зручні для читання людині конструкції, такі як мультиплікатори SI (10k, 40M тощо) і має трохи менше котлован (наприклад, цитати навколо клавіш). Це насправді досить близько до формату файлу конфігурації nginx, якщо ви вже знайомі з цим.


2

Я погоджуюся з немо, і я написав невеликий інструмент, щоб зробити це справді легко.

bitbucket.org/gotamer/cfg - це конфігураційний пакет json

  • Ви визначаєте елементи конфігурації у програмі як структуру.
  • Шаблон файлу конфігурації json з вашої структури зберігається під час першого запуску
  • Ви можете зберегти зміни конфігурації в конфігурації

Див. Приклад


1

Я спробував JSON. Це спрацювало. Але я ненавиджу створювати структуру точних полів і типів, які я можу встановити. Для мене це був біль. Я помітив, що це метод, який застосовують усі параметри конфігурації, які я міг знайти. Можливо, мій досвід динамічних мов робить мене сліпим від переваг такої багатослівності. Я створив новий простий формат конфігураційного файлу та більш динамічну ліштва для його читання.

https://github.com/chrisftw/ezconf

Я досить новачок у світі Go, тому, можливо, це не шлях. Але це працює, він досить швидкий і супер простий у використанні.

Плюси

  • Супер просто
  • Менший код

Мінуси

  • Немає масивів чи типів карт
  • Дуже плоский формат файлу
  • Нестандартні конф-файли
  • У вас є вбудована конвенція, яку я зараз, якщо взагалі нахмурився в спільноті Go. (Шукає конфігураційний файл у конфігураційному каталозі)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.