Как обрабатывать конфигурацию в Go [закрыто]

284

Я новичок в программировании на Go, и мне интересно: каков предпочтительный способ обработки параметров конфигурации для программы на Go ( для чего в других контекстах можно использовать файлы свойств или файлы ini )?

theglauber
источник
Я также начал нить golang-nuts, у которой есть несколько дополнительных идей.
theglauber
2
Я склонен использовать сценарии оболочки и переменные среды.
правостороннее
3
Я посвятил целому посту в блоге « Сохранение конфигурации приложения в Go», где объяснял, как это сделать, с примерами для двух самых популярных форматов: json и YAML. Примеры готовы к производству.
upitau
Для справки: HCL от HashiCorp, который поддерживает комментарии и совместим с JSON и UCL. github.com/hashicorp/hcl
Каве
gobyexample.com/command-line-arguments
Саймон Малкин

Ответы:

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, и это отважное усилие, но я взял отсутствие документации как указание на то, что я должен искать в другом месте. goini - это простая и удобная библиотека для работы с ini- файлами Windows . Был предложен новый формат под названием TOML, но он также имеет проблемы . На этом этапе я бы придерживался JSON или INI .
theglauber
6
YAML поддерживает комментарии, если вы хотите добавлять заметки везде в конфигурационном файле.
Иван Блэк,
43
Для тех, кто читает это и идет по этому пути, будьте осторожны: отсутствие комментариев в JSON делает его непригодным для использования человеком в конфигурационном файле (imo). Это формат обмена данными - вы можете потерять способность писать полезные / описательные комментарии в конфигурационных файлах, что может ухудшить удобство обслуживания («почему этот параметр активирован?», «Что он делает?», «Каковы допустимые значения для него»). ?" и т.д).
Дариан Муди
6
Аааа - я попробовал это в своем коде и забыл определить атрибуты struct заглавными буквами (не экспортируется) - это стоило мне часа моей жизни. Может быть, другие совершают ту же ошибку> будьте
осторожны
6
Вы, вероятно, должны defer file.Close()после проверки open err
Габриэль
97

Другой вариант - использовать TOML , который является INI-подобным форматом, созданным Томом Престоном-Вернером. Я построил парсер Go для него, который тщательно протестирован . Вы можете использовать его, как и другие варианты, предложенные здесь. Например, если у вас есть эти данные TOML вsomething.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
}
BurntSushi5
источник
18
Мне нравится TOML, потому что он позволяет мне писать комментарии либо на новых строках, либо в конце настройки конфигурации строки. Я не могу сделать это с JSON.
sergserg
Каждое обновление конфигурации требует обновления в коде, что очень раздражает.
Hywak
4
Каждый подход к конфигурации делает. Как еще ваша программа узнает о новом конфиге?
BurntSushi5
@ BurntSushi5 могут ли быть дополнительные поля в файле Toml, которые не заботятся о коде? Я имею в виду, можно ли использовать более новую версию файла конфигурации со старой версией кода? В моем случае можно игнорировать неиспользуемые параметры конфигурации.
user1952500
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 с iniflags .

Стандартные флаги go имеют следующие преимущества:

  • Идиоматические.
  • Легко использовать. Флаги могут быть легко добавлены и разбросаны по произвольным пакетам, которые использует ваш проект.
  • Флаги имеют встроенную поддержку значений и описания по умолчанию.
  • Флаги обеспечивают стандартный вывод справки со значениями по умолчанию и описанием.

Единственный недостаток стандартных флагов go - это проблемы управления, когда количество флагов, используемых в вашем приложении, становится слишком большим.

Iniflags элегантно решает эту проблему: просто измените две строки в вашем основном пакете, и он волшебным образом получит поддержку чтения значений флагов из INI-файла. Флаги из INI-файлов могут быть переопределены путем передачи новых значений в командной строке.

См. Также https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE подробности.

valyala
источник
Я начал использовать флаги для проекта, над которым работал (мой первый проект с нуля), но мне интересно, как справиться с такими вещами, как тесты? Например, это клиент API, и я хотел бы использовать флаги, но кажется, что это усложнит мое тестирование ( go testне позволяет передавать флаги), в то время как файл конфигурации не будет.
Зачайсан
установить флаги из тестов несложно:*FlagName = value
Стивен Сорока
9
было бы очень полезно, если бы здесь был подробный пример кода, показывающий рабочий пример :)
zero_cool
Не очень хорошая идея, когда вам нужно поделиться конфигурацией с другими приложениями, написанными на других языках.
Кирзилла
предложил бы использовать pflags вместо флагов. pflags использует стандарт posix
Fjolnir Dvorak
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
}
Rick-777
источник
2
Разве это не то, о чем Аск уже упоминал?
Немо
8

взгляни на гонфиг

// 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)
Кристиан Вестман
источник
Это хорошо, так как мне не нужно переопределять всю конфигурационную структуру в go
thanhpk
5

Я написал простую конфигурационную библиотеку ini на Голанге.

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)
    }
}

=================== Update =======================

В последнее время мне нужен анализатор 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)
}
c4pt0r
источник
4

Вас также может заинтересовать go-libucl , набор привязок Go для UCL, универсальный язык конфигурации. UCL немного похож на JSON, но с лучшей поддержкой для людей: он поддерживает комментарии и удобочитаемые конструкции, такие как множители SI (10k, 40M и т. Д.), И имеет немного меньший шаблон (например, кавычки вокруг ключей). На самом деле это довольно близко к формату файла конфигурации nginx, если вы уже знакомы с этим.

trombonehero
источник
2

Я согласен с Немо и написал небольшой инструмент, чтобы все было по-настоящему легко.

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

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

Смотрите doc.go для примера

RoboTamer
источник
1

Я попробовал JSON. Это сработало. Но я ненавижу создавать структуру точных полей и типов, которые я могу задавать. Для меня это было болью. Я заметил, что это был метод, используемый всеми опциями конфигурации, которые я мог найти. Возможно, мой опыт работы с динамическими языками делает меня слепым к преимуществам такой многословности. Я создал новый простой формат файла конфигурации и более динамическую библиотеку для его чтения.

https://github.com/chrisftw/ezconf

Я довольно новичок в мире Го, так что это может быть не путь Го. Но это работает, это довольно быстро и очень просто в использовании.

Pros

  • Супер просто
  • Меньше кода

Cons

  • Нет массивов или типов карт
  • Очень плоский формат файла
  • Нестандартные файлы conf
  • Есть небольшая встроенная конвенция, которую я сейчас, если вообще не одобряю, в сообществе Go. (Ищет файл конфигурации в каталоге конфигурации)
chrisftw
источник