Cách tiếp cận đúng để đăng nhập toàn cầu trong Golang


119

Mô hình đăng nhập ứng dụng trong Go là gì? Nếu tôi có, chẳng hạn như 5 goroutines tôi cần đăng nhập, tôi có nên ...

  • Tạo một đĩa đơn log.Loggervà chuyển nó đi?
  • Đi qua một con trỏ đến đó log.Logger?
  • Mỗi quy trình hoặc chức năng có nên tạo một trình ghi nhật ký không?
  • Tôi có nên tạo trình ghi nhật ký làm biến toàn cục không?

Câu trả lời:


59
  • Tạo một nhật ký duy nhất. Đăng nhập và chuyển nó đi?

Điều đó là có thể. Một log.Logger có thể được sử dụng đồng thời từ nhiều goroutines.

  • Đi qua một con trỏ đến nhật ký đó.

log.New trả về a *Loggerthường là một dấu hiệu cho thấy bạn nên chuyển đối tượng xung quanh dưới dạng con trỏ. Chuyển nó dưới dạng giá trị sẽ tạo ra một bản sao của cấu trúc (tức là một bản sao của Logger) và sau đó nhiều goroutines có thể ghi đồng thời vào cùng một io.Writer . Đó có thể là một vấn đề nghiêm trọng, tùy thuộc vào cách thực hiện của người viết.

  • Mỗi quy trình hoặc chức năng có nên tạo một trình ghi nhật ký không?

Tôi sẽ không tạo một trình ghi nhật ký riêng cho từng chức năng hoặc quy trình. Goroutines (và các chức năng) được sử dụng cho các tác vụ rất nhẹ sẽ không biện minh cho việc duy trì một trình ghi nhật ký riêng biệt. Có lẽ bạn nên tạo một trình ghi nhật ký cho từng thành phần lớn hơn trong dự án của mình. Ví dụ: nếu dự án của bạn sử dụng dịch vụ SMTP để gửi thư, việc tạo một trình ghi nhật ký riêng cho dịch vụ thư có vẻ là một ý tưởng hay để bạn có thể lọc và tắt đầu ra riêng biệt.

  • Tôi có nên tạo trình ghi nhật ký làm biến toàn cục không?

Điều đó phụ thuộc vào gói của bạn. Trong ví dụ về dịch vụ thư trước, có lẽ bạn nên có một trình ghi nhật ký cho mỗi phiên bản dịch vụ của bạn, để người dùng có thể ghi lại các lỗi khi sử dụng dịch vụ thư gmail khác với các lỗi xảy ra khi sử dụng MTA cục bộ (ví dụ: sendmail ).


37

Đối với các trường hợp đơn giản, có một trình ghi nhật ký chung được xác định trong gói nhật ký log.Logger,. Trình ghi nhật ký toàn cầu này có thể được định cấu hình thông qualog.SetFlags .

Sau đó, người ta chỉ có thể gọi các hàm cấp cao nhất của gói nhật ký như log.Printflog.Fatalf, sử dụng cá thể toàn cục đó.


Nghĩ rằng bạn có thể đặt các cờ mà bạn không thể sử dụng trình ghi nhật ký tùy chỉnh.
0xcaff

@caffinatedmonkey thực sự, bạn có thể sử dụng trình ghi tùy chỉnh nếu chúng triển khai io.Writergiao diện và bạn thay đổi đầu ra của trình ghi mặc định thông qua SetOutput().
congusbongus

16

Đây là một trình ghi nhật ký đơn giản

package customlogger

import (
    "log"
    "os"
    "sync"
)

type logger struct {
    filename string
    *log.Logger
}

var logger *logger
var once sync.Once

// start loggeando
func GetInstance() *logger {
    once.Do(func() {
        logger = createLogger("mylogger.log")
    })
    return logger
}

func createLogger(fname string) *logger {
    file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)

    return &logger{
        filename: fname,
        Logger:   log.New(file, "My app Name ", log.Lshortfile),
    }
}

Bạn có thể sử dụng nó theo cách này

package main

import (
    "customlogger"
    "fmt"
    "net/http"
)

func main() {
    logger := customlogger.GetInstance()
    logger.Println("Starting")

    http.HandleFunc("/", sroot)
    http.ListenAndServe(":8080", nil)
}

func sroot(w http.ResponseWriter, r *http.Request) {
    logger := customlogger.GetInstance()

    fmt.Fprintf(w, "welcome")
    logger.Println("Starting")
}

10

Tôi biết câu hỏi này hơi cũ, nhưng nếu, giống như tôi, các dự án của bạn được tạo thành từ nhiều tệp nhỏ hơn, tôi sẽ bỏ phiếu cho tùy chọn thứ 4 của bạn - Tôi đã tạo một tùy chọn logger.golà một phần của gói chính. Tệp go này tạo ra trình ghi nhật ký, gán nó vào một tệp và cung cấp nó cho phần còn lại của main. Lưu ý rằng tôi chưa nghĩ ra một cách dễ dàng để đóng errorlog ...

package main

import (
    "fmt"
    "log"
    "os"
)

var errorlog *os.File
var logger *log.Logger

func init() {
    errorlog, err := os.OpenFile(logfile,  os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Printf("error opening file: %v", err)
        os.Exit(1)
    }

    logger = log.New(errorlog, "applog: ", log.Lshortfile|log.LstdFlags)
}

8
Đối bế mạc duyên dáng, bạn có thể có thể defer errorlog.Close()vào cuối năm thực hiện, hoặc tốt hơn đảm bảo khép kín, thiết lập xử lý tín hiệu của nó sử dụng gói tín hiệu Go golang.org/pkg/os/signal
Anfernee

4

Đây là một câu hỏi cũ hơn, nhưng tôi muốn đề xuất sử dụng http://github.com/romana/rlog (mà chúng tôi đã phát triển). Nó được cấu hình thông qua các biến môi trường, đối tượng ghi nhật ký được tạo và khởi tạo khi rlog được nhập. Do đó, không cần phải vượt qua một máy ghi nhật ký.

rlog có khá nhiều tính năng:

  • Dấu ngày / giờ có thể định cấu hình đầy đủ
  • Đồng thời xuất ra stderr hoặc stdout cũng như tệp.
  • Các cấp độ nhật ký tiêu chuẩn (Gỡ lỗi, Thông tin, v.v.) cũng như ghi nhật ký nhiều cấp có thể định cấu hình tự do.
  • Ghi nhật ký theo yêu cầu thông tin người gọi (tệp, số đường dây, chức năng).
  • Khả năng thiết lập các cấp độ nhật ký khác nhau cho các tệp nguồn khác nhau.

Nó rất nhỏ, không có phụ thuộc bên ngoài, ngoại trừ thư viện Golang tiêu chuẩn và đang được tích cực phát triển. Ví dụ được cung cấp trong repo.


3
Cảm ơn bạn đã tiết lộ mối quan hệ của bạn với sản phẩm bạn đang giới thiệu! Nó được đánh giá cao.
Robert Columbia

2

Tôi thấy gói nhật ký mặc định ( https://golang.org/pkg/log/ ) hơi hạn chế. Ví dụ: không hỗ trợ thông tin so với nhật ký gỡ lỗi.
Sau một số lần dò xét, hãy quyết định sử dụng https://github.com/golang/glog . Đây dường như là một cổng của https://github.com/google/glog và mang lại sự linh hoạt tốt trong việc ghi nhật ký. Ví dụ: khi chạy một ứng dụng cục bộ, bạn có thể muốn nhật ký mức GỠ LỖI nhưng có thể chỉ muốn chạy ở mức THÔNG TIN / LỖI trong sản xuất. Danh sách các tính năng / hướng dẫn đầy đủ tại đây https://google-glog.googlecode.com/svn/trunk/doc/glog.html (Nó dành cho mô-đun c ++, nhưng phần lớn được dịch sang cổng golang)


0

Một trong những mô-đun ghi nhật ký mà bạn có thể xem xét là klog . Nó hỗ trợ ghi nhật ký 'V' mang lại sự linh hoạt để ghi nhật ký ở mức nhất định

klog là một nhánh của glog và khắc phục những nhược điểm sau

  • glog trình bày rất nhiều "gotchas" và giới thiệu những thách thức trong môi trường container, tất cả đều không được ghi chép đầy đủ.
  • glog không cung cấp một cách dễ dàng để kiểm tra nhật ký, điều này làm giảm tính ổn định của phần mềm sử dụng nó
  • glog dựa trên C ++ và klog là một triển khai golang thuần túy

Thực hiện mẫu

package main

import (
    "flag"

    "k8s.io/klog"


)

type myError struct {
    str string
}

func (e myError) Error() string {
    return e.str
}

func main() {
    klog.InitFlags(nil)
    flag.Set("v", "1")
    flag.Parse()

    klog.Info("hello", "val1", 1, "val2", map[string]int{"k": 1})
    klog.V(3).Info("nice to meet you")
    klog.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14})
    klog.Error(myError{"an error occurred"}, "goodbye", "code", -1)
    klog.Flush()
}

0

Tôi mời bạn xem lại Blog của tôi, nơi tôi giải thích việc sử dụng LOG với GOlang: https://su9.co/9BAE74B

Ví dụ: // Se khai báo biến Log. Esta será usada para nhà đăng ký los eventos. var (Log * log.Logger = Loggerx ())

func Loggerx() *log.Logger {
    LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
        //En el caso que la variable de entorno exista, el sistema usa la configuración del docker.
    if LOG_FILE_LOCATION == "" {
        LOG_FILE_LOCATION = "../logs/" + APP_NAME + ".log"
    } else {
        LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + ".log"
    }
    flag.Parse()
        //Si el archivo existe se rehusa, es decir, no elimina el archivo log y crea uno nuevo.
    if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
        file, err1 := os.Create(LOG_FILE_LOCATION)
        if err1 != nil {
            panic(err1)
        }
                //si no existe,se crea uno nuevo.
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    } else {
                //si existe se rehusa.
        file, err := os.OpenFile(LOG_FILE_LOCATION, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
        if err != nil {
            panic(err)
        }
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.