Bagaimana menangani konfigurasi di Go [closed]

284

Saya baru di pemrograman Go, dan saya bertanya-tanya: apa cara yang disukai untuk menangani parameter konfigurasi untuk program Go (jenis barang yang mungkin menggunakan file properti atau file ini untuk, dalam konteks lain)?

theglauber
sumber
Saya juga memulai thread golang-kacang yang memiliki beberapa ide tambahan.
theglauber
2
Saya cenderung menggunakan skrip shell dan variabel lingkungan.
rightfold
3
Saya mengabdikan seluruh posting blog Konfigurasi Aplikasi Berkelanjutan Di mana saya menjelaskan bagaimana melakukannya dengan contoh untuk dua format paling populer: json dan YAML. Contohnya adalah siap produksi.
upitau
Sebagai catatan ada HCL dari HashiCorp yang mendukung komentar dan kompatibel dengan JSON dan UCL. github.com/hashicorp/hcl
Kaveh Shahbazian

Jawaban:

244

The JSON Format bekerja untuk saya cukup baik. Pustaka standar menawarkan metode untuk menulis indentasi struktur data, sehingga cukup mudah dibaca.

Lihat juga benang golang-kacang ini .

Manfaat JSON adalah cukup mudah untuk mem-parsing dan dapat dibaca / diedit oleh manusia sambil menawarkan semantik untuk daftar dan pemetaan (yang dapat menjadi sangat berguna), yang tidak demikian dengan banyak parser konfigurasi tipe-in.

Contoh penggunaan:

conf.json :

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

Program untuk membaca konfigurasi

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]
nemo
sumber
6
Tampaknya JSON adalah yang paling buruk dari alternatif saat ini. Saya melihat ke go-yaml dan ini merupakan upaya yang berani, tetapi saya menganggap kurangnya dokumentasi sebagai indikasi bahwa saya harus mencari di tempat lain. goini tampaknya menjadi perpustakaan yang sederhana dan mudah untuk menangani file Windows ini . Format baru yang disebut TOML telah diusulkan, tetapi juga memiliki masalah . Pada titik ini saya akan tetap menggunakan JSON atau ini .
theglauber
6
YAML mendukung komentar, jika Anda ingin menambahkan catatan di mana-mana dalam file konfigurasi.
Ivan Black
42
Bagi mereka yang membaca ini dan menuruni rute itu, berhati-hatilah: Tidak adanya komentar JSON membuatnya tidak cocok untuk file konfigurasi yang dapat digunakan manusia (imo). Ini adalah format pertukaran data - Anda mungkin menemukan kehilangan kemampuan untuk menulis komentar yang membantu / deskriptif dalam file konfigurasi dapat merusak pemeliharaan ("mengapa pengaturan ini diaktifkan?", "Apa fungsinya?", "Apa nilai yang valid untuk itu ? "dll).
Darian Moody
6
Ahhh - Saya mencoba itu dalam kode saya dan lupa untuk mendefinisikan atribut struct dengan huruf besar (tidak diekspor) - ini menghabiskan satu jam dalam hidup saya. Mungkin orang lain melakukan kesalahan yang sama> diperingatkan; D
JohnGalt
6
Anda mungkin harus defer file.Close()setelah memeriksa kesalahan terbuka
Gabriel
97

Pilihan lain adalah menggunakan TOML , yang merupakan format seperti INI yang dibuat oleh Tom Preston-Werner. Saya membuat parser Go untuk itu yang diuji secara ekstensif . Anda dapat menggunakannya seperti opsi lain yang diusulkan di sini. Misalnya, jika Anda memiliki data TOML ini disomething.toml

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

Kemudian Anda dapat memuatnya ke program Go Anda dengan sesuatu seperti

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
sumber
18
Saya suka TOML karena memungkinkan saya menulis komentar di baris baru atau di akhir pengaturan konfigurasi garis. Saya tidak bisa melakukannya dengan JSON.
sergserg
Setiap pembaruan konfigurasi memerlukan pembaruan dalam kode yang sangat menjengkelkan.
hywak
4
Setiap pendekatan untuk config tidak. Bagaimana lagi program Anda mengetahui konfigurasi baru?
BurntSushi5
@ BurntSushi5 dapatkah ada bidang tambahan dalam file Toml yang tidak dipedulikan oleh kode? Maksud saya, bisakah versi file konfigurasi yang lebih baru digunakan dengan versi kode yang lebih lama? Tidak masalah dalam kasus saya untuk mengabaikan opsi konfigurasi yang tidak digunakan.
user1952500
2
saya suka itu. Kerja bagus. Secara pribadi saya pikir lebih mudah bagi admin atau pelanggan untuk mengubah file TOML daripada JSON.
blndev
49

Viper adalah sistem manajemen konfigurasi golang yang bekerja dengan JSON, YAML, dan TOML. Terlihat sangat menarik.

Mikha
sumber
1
Terutama layak untuk aplikasi 12factor 12factor.net
DerKnorr
Gunakan gonfig untuk konfigurasi JSON di Go. github.com/eduardbcom/gonfig
Eduard Bondarenko
1
Jangan gunakan Viper, bukan thread-safe yang hampir memecat saya.
igonejack
@igonejack Berikan contoh di mana Viper menggigit Anda?
Dr.eel
1
@ Dr.eel Coba pisahkan viper.GetBool ("abc") dan Viper.Set ("abc", false) di goroutine yang berbeda.
igonejack
44

Saya biasanya menggunakan JSON untuk struktur data yang lebih rumit. The downside adalah bahwa Anda dengan mudah berakhir dengan sekelompok kode untuk memberi tahu pengguna di mana kesalahan itu, berbagai kasus tepi dan apa yang tidak.

Untuk konfigurasi dasar (kunci api, nomor port, ...) Saya sudah sangat beruntung dengan paket gcfg . Ini didasarkan pada format git config.

Dari dokumentasi:

Konfigurasi sampel:

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

Go struct:

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

Dan kode yang diperlukan untuk membacanya:

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

Ini juga mendukung nilai slice, sehingga Anda dapat mengizinkan menentukan kunci beberapa kali dan fitur bagus lainnya seperti itu.

Tanyakan Bjørn Hansen
sumber
4
Penulis asli gcfg menghentikan proyek dan memulai sconf lain yang terkait .
iwat
39

Cukup gunakan flag go standar dengan iniflags .

Bendera go standar memiliki manfaat berikut:

  • Idiomatis.
  • Mudah digunakan. Bendera dapat dengan mudah ditambahkan dan tersebar di seluruh paket sewenang-wenang yang digunakan proyek Anda.
  • Bendera memiliki dukungan out-of-the-box untuk nilai dan deskripsi default.
  • Bendera memberikan output 'bantuan' standar dengan nilai dan deskripsi default.

Satu-satunya kelemahan standar go flag miliki - adalah masalah manajemen ketika jumlah flag yang digunakan dalam aplikasi Anda menjadi terlalu besar.

Iniflags secara elegan menyelesaikan masalah ini: cukup modifikasi dua baris dalam paket utama Anda dan secara ajaib mendapatkan dukungan untuk membaca nilai flag dari file ini. Panji dari file ini dapat diganti dengan memberikan nilai baru dalam baris perintah.

Lihat juga https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE untuk detailnya.

valyala
sumber
Saya mulai menggunakan bendera untuk proyek yang telah saya kerjakan (proyek golang dari awal saya), tetapi saya bertanya-tanya bagaimana cara menangani hal-hal seperti tes? Sebagai contoh, ini adalah klien api, dan saya ingin menggunakan flag, tetapi sepertinya itu akan mempersulit pengujian saya ( go testjangan biarkan saya melewati flag) sementara file config tidak.
zachaysan
pengaturan bendera dari tes mudah:*FlagName = value
Steven Soroka
9
akan sangat membantu jika ada contoh kode rinci di sini menunjukkan contoh yang bekerja :)
zero_cool
Bukan ide yang baik ketika Anda perlu berbagi konfigurasi dengan aplikasi lain yang ditulis dalam bahasa lain.
Kirzilla
menyarankan untuk menggunakan pflags alih-alih flag. pflags menggunakan posix-standard
Fjolnir Dvorak
12

Saya sudah mulai menggunakan Gcfg yang menggunakan file seperti ini. Sederhana - jika Anda menginginkan sesuatu yang sederhana, ini adalah pilihan yang baik.

Berikut kode pemuatan yang saya gunakan saat ini, yang memiliki pengaturan default dan memungkinkan bendera baris perintah (tidak ditampilkan) yang menimpa beberapa konfigurasi saya:

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
sumber
2
Bukankah ini persis yang sudah disebutkan oleh Ask?
nemo
8

lihat di 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)
Christian Westman
sumber
Yang ini bagus, karena saya tidak perlu mendefinisikan ulang seluruh struktur konfigurasi dalam go
thanhpk
5

Saya menulis perpustakaan konfigurasi ini di golang.

https://github.com/c4pt0r/cfg

goroutine-safe, mudah digunakan

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

=================== Perbarui =======================

Baru-baru ini saya membutuhkan parser INI dengan dukungan bagian, dan saya menulis paket sederhana:

github.com/c4pt0r/cfg

Anda dapat menguraikan INI seperti menggunakan paket "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
sumber
4

Anda mungkin juga tertarik dengan go-libucl , sekumpulan Go bindings untuk UCL, Bahasa Konfigurasi Universal. UCL sedikit mirip dengan JSON, tetapi dengan dukungan yang lebih baik untuk manusia: mendukung komentar dan konstruksi yang dapat dibaca manusia seperti pengganda SI (10k, 40M, dll.) Dan memiliki pelat boiler yang sedikit lebih sedikit (misalnya, kutipan di sekitar kunci). Ini sebenarnya cukup dekat dengan format file konfigurasi nginx, jika Anda sudah terbiasa dengan itu.

trombonehero
sumber
2

Saya setuju dengan nemo dan saya menulis sedikit alat untuk membuatnya semuanya mudah.

bitbucket.org/gotamer/cfg adalah paket konfigurasi json

  • Anda mendefinisikan item konfigurasi di aplikasi Anda sebagai struct.
  • Templat file konfigurasi json dari struct Anda disimpan pada proses pertama
  • Anda dapat menyimpan modifikasi runtime ke konfigurasi

Lihat doc.go untuk contoh

RoboTamer
sumber
1

Saya mencoba JSON. Itu berhasil. Tapi saya benci harus membuat struct dari bidang dan tipe yang tepat yang mungkin saya atur. Bagi saya itu menyakitkan. Saya perhatikan itu adalah metode yang digunakan oleh semua opsi konfigurasi yang bisa saya temukan. Mungkin latar belakang saya dalam bahasa yang dinamis membuat saya buta akan manfaat dari kata-kata seperti itu. Saya membuat format file konfigurasi sederhana yang baru, dan lib ish yang lebih dinamis untuk membacanya.

https://github.com/chrisftw/ezconf

Saya cukup baru di dunia Go, jadi mungkin bukan jalan Go. Tapi itu berhasil, cukup cepat, dan super mudah digunakan.

Pro

  • Sangat sederhana
  • Kode lebih sedikit

Cons

  • Tidak ada susunan atau tipe peta
  • Format file sangat datar
  • File conf non-standar
  • Apakah memiliki sedikit konvensi built-in, yang saya sekarang jika disukai secara umum di komunitas Go. (Mencari file config di direktori config)
chrisftw
sumber