วิธีจัดการการกำหนดค่าใน Go [ปิด]


284

ฉันใหม่ในการเขียนโปรแกรม Go และฉันสงสัยว่า: วิธีใดที่เหมาะสมในการจัดการพารามิเตอร์การกำหนดค่าสำหรับโปรแกรม Go (ประเภทของสิ่งหนึ่งที่อาจใช้ไฟล์คุณสมบัติหรือไฟล์iniสำหรับในบริบทอื่น ๆ )?


ฉันเริ่มกระทู้ golang-nutsซึ่งมีแนวคิดเพิ่มเติมเล็กน้อย
theglauber

2
ฉันมักจะใช้เชลล์สคริปต์และตัวแปรสภาพแวดล้อม
rightfold

3
ฉันทุ่มเทโพสต์บล็อกทั้งหมดPersisting Application Configuration In Goที่ซึ่งฉันได้อธิบายวิธีการทำด้วยตัวอย่างสำหรับสองรูปแบบที่นิยมมากที่สุด: json และ YAML ตัวอย่างคือการผลิตพร้อม
upitau

สำหรับบันทึกนั้นมี HCL จาก HashiCorp ที่รองรับความคิดเห็นและรองรับ JSON และ UCL github.com/hashicorp/hcl
Kaveh Shahbazian

คำตอบ:


244

JSONรูปแบบทำงานให้ฉันได้ค่อนข้างดี ไลบรารีมาตรฐานเสนอวิธีการในการเขียนโครงสร้างข้อมูลที่มีการเยื้องจึงค่อนข้างอ่านได้

ดูเพิ่มเติมด้าย golang ถั่วนี้

ประโยชน์ของ JSON คือการแยกวิเคราะห์และอ่าน / แก้ไขได้ง่ายในขณะที่ให้ความหมายสำหรับรายการและการแมป (ซึ่งอาจเป็นประโยชน์มาก) ซึ่งไม่ใช่กรณีที่มี parsers config แบบ 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ดูเหมือนจะเป็นไลบรารีที่ง่ายและสะดวกในการจัดการไฟล์Windows ini มีการเสนอรูปแบบใหม่ที่เรียกว่า TOML แต่ก็มีปัญหาเช่นกัน ณ จุดนี้ผมจะติด JSON หรือINI
theglauber

6
YAML สนับสนุนความคิดเห็นหากคุณต้องการเพิ่มบันทึกทุกที่ในไฟล์ปรับแต่ง
Ivan Black

43
สำหรับผู้ที่กำลังอ่านข้อความนี้และลงเส้นทางนั้นระวัง: การขาดความเห็นของ JSON ทำให้ไม่เหมาะสมสำหรับไฟล์การกำหนดค่าที่มนุษย์ใช้งานได้ (imo) มันเป็นรูปแบบการแลกเปลี่ยนข้อมูล - คุณอาจพบว่าการสูญเสียความสามารถในการเขียนความคิดเห็นที่เป็นประโยชน์ / คำอธิบายในไฟล์กำหนดค่าอาจทำให้การบำรุงรักษาเสียหายได้ ("เหตุใดการตั้งค่านี้จึงเปิดใช้งาน?", " ? "ฯลฯ )
Darian Moody

6
Ahhh - ฉันลองในรหัสของฉันและลืมกำหนดแอตทริบิวต์ struct ด้วยตัวอักษรตัวพิมพ์ใหญ่ (ไม่ส่งออก) - ฉันเสียค่าใช้จ่ายหนึ่งชั่วโมงในชีวิตของฉัน บางทีคนอื่น ๆ ทำผิดพลาดเหมือนเดิม> ได้รับการเตือน D
JohnGalt

6
คุณน่าจะdefer file.Close()หลังจากตรวจสอบข้อผิดพลาดที่เปิดอยู่
Gabriel

97

อีกทางเลือกหนึ่งคือใช้TOMLซึ่งเป็นรูปแบบ INI ที่สร้างโดย Tom Preston-Werner ฉันสร้าง parser ไปได้ที่มีการทดสอบอย่างกว้างขวาง คุณสามารถใช้งานได้เหมือนกับตัวเลือกอื่น ๆ ที่เสนอไว้ที่นี่ ตัวอย่างเช่นหากคุณมีข้อมูล 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
}

18
ฉันชอบ TOML เพราะมันช่วยให้ฉันสามารถเขียนความคิดเห็นในบรรทัดใหม่หรือที่ส่วนท้ายของการตั้งค่าการกำหนดบรรทัด ฉันไม่สามารถทำได้ด้วย JSON
sergserg

การอัพเดทการกำหนดค่าแต่ละครั้งต้องมีการอัพเดทในโค้ดสิ่งที่น่ารำคาญมาก
hywak

4
ทุกวิธีในการปรับแต่งทำได้ โปรแกรมของคุณจะรับรู้ถึงการกำหนดค่าใหม่ได้อย่างไร
BurntSushi5

@ BurntSushi5 สามารถมีฟิลด์พิเศษในไฟล์ Toml ที่รหัสไม่สนใจได้หรือไม่? ฉันหมายถึงไฟล์ปรับแต่งเวอร์ชันใหม่กว่าสามารถใช้กับรหัสรุ่นเก่ากว่าได้หรือไม่ ในกรณีของฉันจะไม่สนใจตัวเลือกการกำหนดค่าที่ไม่ได้ใช้
user1952500

2
ฉันชอบมัน. การทำงานที่ดี. โดยส่วนตัวฉันคิดว่ามันง่ายกว่าสำหรับผู้ดูแลระบบหรือลูกค้าที่จะเปลี่ยนไฟล์ TOML กว่า JSON
blndev

49

Viperเป็นระบบจัดการการกำหนดค่า golang ที่ทำงานร่วมกับ JSON, YAML และ TOML มันดูน่าสนใจทีเดียว


1
ทำงานได้เป็นพิเศษสำหรับการใช้งาน12factor 12factor.net
DerKnorr

ใช้ gonfig สำหรับการกำหนดค่า JSON ใน Go github.com/eduardbcom/gonfig
Eduard Bondarenko

1
อย่าใช้ Viper เพราะมันไม่ได้ปลอดภัยสำหรับเธรด
igonejack

@igonejack กรุณาให้ตัวอย่างที่ไวเปอร์กัดคุณหรือไม่
Dr.eel

1
@ Dr.eel ลองแยก viper.GetBool ("abc") และ Viper.Set ("abc", false) ใน goroutine ที่แตกต่างกัน
igonejack

44

ฉันมักจะใช้ JSON สำหรับโครงสร้างข้อมูลที่ซับซ้อนมากขึ้น ข้อเสียคือคุณท้ายรหัสได้ง่าย ๆ เพื่อบอกผู้ใช้ว่าเกิดข้อผิดพลาดกรณีขอบต่าง ๆ และอะไรบ้าง

สำหรับการตั้งค่าพื้นฐาน (คีย์ api, หมายเลขพอร์ต, ... ) ฉันโชคดีมากกับแพ็คเกจgcfg มันขึ้นอยู่กับรูปแบบการกำหนดค่า git

จากเอกสาร:

ตัวอย่างการกำหนดค่า:

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

ไป struct:

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

และรหัสที่จำเป็นในการอ่าน:

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

นอกจากนี้ยังรองรับค่าชิ้นดังนั้นคุณสามารถอนุญาตให้ระบุคีย์ได้หลายครั้งและคุณสมบัติที่ดีอื่น ๆ เช่นนั้น


4
ผู้เขียนต้นฉบับของgcfgยกเลิกโครงการและเริ่มต้นอีกหนึ่งที่เกี่ยวข้องกับsconf
iwat

39

เพียงแค่ใช้มาตรฐานธงไปกับiniflags

ธงแบบมาตรฐานไปมีประโยชน์ดังต่อไปนี้:

  • เป็นสำนวน
  • ง่ายต่อการใช้. สามารถเพิ่มและกระจายค่าสถานะได้อย่างง่ายดายในแพ็คเกจที่โครงการของคุณใช้
  • ค่าสถานะมีการสนับสนุนนอกกรอบสำหรับค่าเริ่มต้นและคำอธิบาย
  • แฟล็กให้เอาต์พุต 'วิธีใช้' มาตรฐานพร้อมค่าเริ่มต้นและคำอธิบาย

ข้อเสียเปรียบธงมาตรฐานแบบย้อนกลับเท่านั้นที่มี - คือปัญหาการจัดการเมื่อจำนวนของค่าสถานะที่ใช้ในแอปของคุณใหญ่เกินไป

Iniflags แก้ปัญหานี้ได้อย่างหรูหรา: เพียงแค่แก้ไขสองบรรทัดในแพ็คเกจหลักของคุณและมันจะได้รับการสนับสนุนอย่างน่าอัศจรรย์สำหรับการอ่านค่าสถานะจากไฟล์ ini การตั้งค่าสถานะจากไฟล์ ini สามารถ overriden โดยผ่านค่าใหม่ในบรรทัดคำสั่ง

ดูเพิ่มเติมที่https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQEสำหรับรายละเอียด


ฉันเริ่มใช้แฟล็กสำหรับโปรเจ็กต์ที่ฉันทำงานอยู่ (โปรเจกต์เกาแรกของฉัน) แต่ฉันสงสัยว่าจะจัดการกับสิ่งต่าง ๆ เช่นการทดสอบได้อย่างไร ตัวอย่างเช่นนี่คือไคลเอนต์ api และฉันต้องการใช้ค่าสถานะ แต่ดูเหมือนว่าจะทำให้การทดสอบของฉันยุ่งยาก ( go testไม่อนุญาตให้ฉันส่งผ่านค่าสถานะ) ในขณะที่ไฟล์ปรับแต่งจะไม่ทำงาน
zachaysan

การตั้งค่าสถานะจากการทดสอบนั้นง่าย:*FlagName = value
Steven Soroka

9
จะมีประโยชน์มากหากมีรหัสตัวอย่างแบบละเอียดที่นี่แสดงตัวอย่างการทำงาน :)
zero_cool

ไม่ใช่ความคิดที่ดีเมื่อคุณต้องการแชร์การกำหนดค่ากับแอปพลิเคชันอื่นที่เขียนด้วยภาษาอื่น
Kirzilla

จะแนะนำให้ใช้ pflags แทนธง pflags ใช้มาตรฐาน posix
Fjolnir Dvorak

12

ฉันเริ่มใช้Gcfgซึ่งใช้ไฟล์ Ini-like มันง่าย - ถ้าคุณต้องการอะไรที่เรียบง่ายนี่เป็นตัวเลือกที่ดี

นี่คือรหัสการโหลดที่ฉันใช้อยู่ในปัจจุบันซึ่งมีการตั้งค่าเริ่มต้นและอนุญาตให้ใช้แฟล็กบรรทัดคำสั่ง (ไม่แสดง) ที่แทนที่การตั้งค่าบางอย่างของฉัน:

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
นี่ไม่ใช่สิ่งที่ถามไว้แล้วใช่หรือไม่
nemo

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)

อันนี้ดีเพราะฉันไม่ต้องกำหนดโครงสร้างการกำหนดค่าใหม่ทั้งหมดใน go
thanhpk



5

ฉันเขียนไลบรารี่ของ ini config ใน golang

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 ภาษา Universal Configuration UCL เป็นเหมือน JSON แต่ด้วยการสนับสนุนที่ดีกว่าสำหรับมนุษย์: รองรับความคิดเห็นและโครงสร้างที่มนุษย์อ่านได้เช่น SI ทวีคูณ (10k, 40M, ฯลฯ ) และมีสำเร็จรูปน้อยกว่าเล็กน้อย (เช่นคำพูดรอบคีย์) ที่จริงแล้วมันค่อนข้างใกล้เคียงกับรูปแบบไฟล์กำหนดค่า nginx หากคุณคุ้นเคยกับมันแล้ว


2

ฉันเห็นด้วยกับnemoและฉันเขียนเครื่องมือเล็กน้อยเพื่อให้ง่ายขึ้น

bitbucket.org/gotamer/cfgเป็นแพ็คเกจการกำหนดค่า json

  • คุณกำหนดรายการกำหนดค่าในแอปพลิเคชันของคุณเป็นโครงสร้าง
  • เท็มเพลตไฟล์ json config จาก struct ของคุณจะถูกบันทึกในการเรียกใช้ครั้งแรก
  • คุณสามารถบันทึกการแก้ไขรันไทม์ลงในการกำหนดค่า

ดู doc.go สำหรับตัวอย่าง


1

ฉันลอง JSON มันได้ผล แต่ฉันเกลียดที่จะต้องสร้างโครงสร้างของฟิลด์และประเภทที่แน่นอนที่ฉันอาจตั้งค่า สำหรับฉันนั่นเป็นความเจ็บปวด ฉันสังเกตว่ามันเป็นวิธีการที่ใช้โดยตัวเลือกการกำหนดค่าทั้งหมดที่ฉันสามารถหาได้ บางทีภูมิหลังของฉันในภาษาแบบไดนามิกอาจทำให้ฉันตาบอดกับประโยชน์ของการใช้คำฟุ่มเฟื่อยดังกล่าว ฉันสร้างรูปแบบไฟล์กำหนดค่าแบบง่ายและ lib-ish แบบไดนามิกมากขึ้นสำหรับการอ่านออก

https://github.com/chrisftw/ezconf

ฉันค่อนข้างใหม่สำหรับโลก Go ดังนั้นอาจไม่ใช่วิธี Go แต่มันใช้งานได้มันค่อนข้างเร็วและใช้ง่ายสุด ๆ

ข้อดี

  • ง่ายสุด ๆ
  • รหัสน้อย

จุดด้อย

  • ไม่มีอาเรย์หรือประเภทแผนที่
  • รูปแบบไฟล์เรียบมาก
  • ไฟล์ conf ที่ไม่ได้มาตรฐาน
  • มีการประชุมในตัวเล็กน้อยซึ่งตอนนี้ถ้าฉันขมวดคิ้วโดยทั่วไปในชุมชนโก (ค้นหาไฟล์กำหนดค่าในไดเรกทอรีกำหนดค่า)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.