主頁 > 後端開發 > Go 語言之 zap 日志庫簡單使用

Go 語言之 zap 日志庫簡單使用

2023-06-18 07:39:24 後端開發

Go 語言之 zap 日志庫簡單使用

默認的 Go log

log:https://pkg.go.dev/log

package main

import (
	"log"
	"os"
)

func init() {
	log.SetPrefix("LOG: ") // 設定前綴

	f, err := os.OpenFile("./log.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("open log file failed with error: %v", err)
	}
	log.SetOutput(f) // 設定輸出

	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile)

	// const (
	// 	Ldate         = 1 << iota // 1 << 0 = 000000001 = 1
	// 	Ltime                     // 1 << 1 = 000000010 = 2
	// 	Lmicroseconds             // 1 << 2 = 000000100 = 4
	// 	Llongfile                 // 1 << 3 = 000001000 = 8
	// 	Lshortfile                // 1 << 4 = 000010000 = 16
	// 	...
	// )
}

func main() {
	log.Println("1234")

	// log.Fatalln("1234")

	// log.Panicln("1234")

	// log.Panic("1234")
	// log.Panicf("1234, %d", 5678)
}

log 包是一個簡單的日志包,

Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined 'standard' Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message. Every log message is output on a separate line: if the message being printed does not end in a newline, the logger will add one. The Fatal functions call os.Exit(1) after writing the log message. The Panic functions call panic after writing the log message.

uber-go zap

log:https://pkg.go.dev/log

github zap:https://github.com/uber-go/zap

pkg zap:https://pkg.go.dev/go.uber.org/zap#section-readme

Blazing fast, structured, leveled logging in Go.

安裝

go get -u go.uber.org/zap

在性能良好但不是關鍵的背景關系中,使用 SugaredLogger,它比其他結構化日志包快4-10倍,包括結構化和 printf 風格的 API,

logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
  // Structured context as loosely typed key-value pairs.
  "url", url,
  "attempt", 3,
  "backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)

當性能和型別安全至關重要時,請使用Logger,它甚至比SugaredLogger 更快,分配也少得多,但它只支持結構化日志記錄,

logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
  // Structured context as strongly typed Field values.
  zap.String("url", url),
  zap.Int("attempt", 3),
  zap.Duration("backoff", time.Second),
)

zap檔案:https://pkg.go.dev/go.uber.org/zap#section-readme

Logger 簡單使用

package main

import (
	"go.uber.org/zap"
	"net/http"
)

// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger

func main() {
	// 初始化
	InitLogger()
	// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
	// 在程式退出之前,把緩沖區里的日志刷到磁盤上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
	// It's a shortcut for NewProductionConfig().Build(...Option).
	logger, _ = zap.NewProduction()
}

func simpleHttpGet(url string) {
	// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		logger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		logger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

運行

Code/go/zap_demo via ?? v1.20.3 via ?? base took 11.0s 
? go run main.go 
{"level":"error","ts":1686929392.121357,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.google.com","error":"Get \"www.google.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"error","ts":1686929422.123222,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"http://www.google.com","error":"Get \"http://www.google.com\": dial tcp 103.252.115.59:80: i/o timeout","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:22\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}

Code/go/zap_demo via ?? v1.20.3 via ?? base took 30.3s 
? go run main.go
{"level":"error","ts":1686929534.4672909,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.baidu.com","error":"Get \"www.baidu.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686929535.561184,"caller":"zap_demo/main.go:47","msg":"Success..","statusCode":"200 OK","url":"http://www.baidu.com"}

Code/go/zap_demo via ?? v1.20.3 via ?? base 
? 

原始碼

// Level reports the minimum enabled level for this logger.
//
// For NopLoggers, this is [zapcore.InvalidLevel].
func (log *Logger) Level() zapcore.Level {
	return zapcore.LevelOf(log.core)
}

// Check returns a CheckedEntry if logging a message at the specified level
// is enabled. It's a completely optional optimization; in high-performance
// applications, Check can help avoid allocating a slice to hold fields.
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
	return log.check(lvl, msg)
}

// Log logs a message at the specified level. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Log(lvl zapcore.Level, msg string, fields ...Field) {
	if ce := log.check(lvl, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Debug(msg string, fields ...Field) {
	if ce := log.check(DebugLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Info(msg string, fields ...Field) {
	if ce := log.check(InfoLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Warn(msg string, fields ...Field) {
	if ce := log.check(WarnLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Error(msg string, fields ...Field) {
	if ce := log.check(ErrorLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func (log *Logger) DPanic(msg string, fields ...Field) {
	if ce := log.check(DPanicLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func (log *Logger) Panic(msg string, fields ...Field) {
	if ce := log.check(PanicLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (log *Logger) Fatal(msg string, fields ...Field) {
	if ce := log.check(FatalLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

每個zapcore.Field其實就是一組鍵值對引數,

// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field

輸出的是 JSON 格式的日志

SugaredLogger 簡單使用

NewProduction

package main

import (
	"go.uber.org/zap"
	"net/http"
)

// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger

var sugarLogger *zap.SugaredLogger

func main() {
	// 初始化
	InitLogger()
	// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
	// 在程式退出之前,把緩沖區里的日志刷到磁盤上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
	// It's a shortcut for NewProductionConfig().Build(...Option).
	logger, _ = zap.NewProduction()
	sugarLogger = logger.Sugar()
}

func simpleHttpGet(url string) {
	// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		//logger.Error(
		sugarLogger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		//logger.Info("Success..",
		sugarLogger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

運行

Code/go/zap_demo via ?? v1.20.3 via ?? base 
? go run main.go
{"level":"error","ts":1686930454.798492,"caller":"zap_demo/main.go:47","msg":"Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0  Get \"www.baidu.com\": unsupported protocol scheme \"\"}","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:47\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:23\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686930454.83406,"caller":"zap_demo/main.go:54","msg":"Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}"}

Code/go/zap_demo via ?? v1.20.3 via ?? base 
? 

NewDevelopment

package main

import (
	"go.uber.org/zap"
	"net/http"
)

// 定義一個全域 logger 實體
// Logger提供快速、分級、結構化的日志記錄,所有方法對于并發使用都是安全的,
// Logger是為每一微秒和每一個分配都很重要的背景關系設計的,
// 因此它的API有意傾向于性能和型別安全,而不是簡便性,
// 對于大多數應用程式,SugaredLogger在性能和人體工程學之間取得了更好的平衡,
var logger *zap.Logger

// SugaredLogger將基本的Logger功能封裝在一個較慢但不那么冗長的API中,任何Logger都可以通過其Sugar方法轉換為sugardlogger,
//與Logger不同,SugaredLogger并不堅持結構化日志記錄,對于每個日志級別,它公開了四個方法:
//   - methods named after the log level for log.Print-style logging
//   - methods ending in "w" for loosely-typed structured logging
//   - methods ending in "f" for log.Printf-style logging
//   - methods ending in "ln" for log.Println-style logging

// For example, the methods for InfoLevel are:
//
//	Info(...any)           Print-style logging
//	Infow(...any)          Structured logging (read as "info with")
//	Infof(string, ...any)  Printf-style logging
//	Infoln(...any)         Println-style logging
var sugarLogger *zap.SugaredLogger

func main() {
	// 初始化
	InitLogger()
	// Sync呼叫底層Core的Sync方法,重繪所有緩沖的日志條目,應用程式在退出之前應該注意呼叫Sync,
	// 在程式退出之前,把緩沖區里的日志刷到磁盤上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction構建了一個合理的生產Logger,它將infollevel及以上的日志以JSON的形式寫入標準錯誤,
	// It's a shortcut for NewProductionConfig().Build(...Option).
	//logger, _ = zap.NewProduction()
	// NewDevelopment構建一個開發日志,它以一種人性化的格式將DebugLevel及以上的日志寫入標準錯誤,
	logger, _ = zap.NewDevelopment()
	// Sugar封裝了Logger,以提供更符合人體工程學的API,但速度略慢,糖化一個Logger的成本非常低,
	// 因此一個應用程式同時使用Logger和sugaredlogger是合理的,在性能敏感代碼的邊界上在它們之間進行轉換,
	sugarLogger = logger.Sugar()
}

func simpleHttpGet(url string) {
	// Get向指定的URL發出Get命令,如果回應是以下重定向代碼之一,則Get跟隨重定向,最多可重定向10個:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do來發出帶有自定義頭的請求,
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		//logger.Error(
		
		// 錯誤使用fmt,以Sprint方式構造和記錄訊息,
		sugarLogger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字串用給定的鍵和值構造一個欄位,
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel記錄訊息,該訊息包括在日志站點傳遞的任何欄位,以及日志記錄器上積累的任何欄位,
		//logger.Info("Success..",
		
		// Info使用fmt,以Sprint方式構造和記錄訊息,
		sugarLogger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

運行

Code/go/zap_demo via ?? v1.20.3 via ?? base 
? go run main.go
2023-06-16T23:52:00.384+0800    ERROR   zap_demo/main.go:48     Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0  Get "www.baidu.com": unsupported protocol scheme ""}
main.simpleHttpGet
        /Users/qiaopengjun/Code/go/zap_demo/main.go:48
main.main
        /Users/qiaopengjun/Code/go/zap_demo/main.go:23
runtime.main
        /usr/local/go/src/runtime/proc.go:250
2023-06-16T23:52:00.439+0800    INFO    zap_demo/main.go:55     Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}

Code/go/zap_demo via ?? v1.20.3 via ?? base 
? 

本文來自博客園,作者:尋月隱君,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17487169.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555438.html

標籤:其他

上一篇:Scala面向物件

下一篇:返回列表

標籤雲
其他(161179) Python(38240) JavaScript(25504) Java(18245) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7256) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4601) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Go 語言之 zap 日志庫簡單使用

    # Go 語言之 zap 日志庫簡單使用 ## 默認的 Go log log:https://pkg.go.dev/log ```go package main import ( "log" "os" ) func init() { log.SetPrefix("LOG: ") // 設定前綴 f, ......

    uj5u.com 2023-06-18 07:39:24 more
  • Scala面向物件

    # 類和物件 **組成結構** ? 建構式: 在創建物件的時候給屬性賦值 ? 成員變數: ? 成員方法(函式) ? 區域變數 ? 代碼塊 ## 構造器 每個類都有一個主構造器,這個構造器和類定義"交織"在一起類名后面的內容就是主構造器,如果引數串列為空的話,()可以省略 scala的類有且僅有一個 ......

    uj5u.com 2023-06-18 07:39:00 more
  • 基于回歸分析的波士頓房價分析

    #基于回歸分析的波士頓房價分析 專案實作步驟: 1.專案結構 2.處理資料 3.處理繪圖 4.對資料進行分析 5.結果展示 一.專案結構 ![image](https://img2023.cnblogs.com/blog/3047082/202306/3047082-2023061722315431 ......

    uj5u.com 2023-06-18 07:38:30 more
  • 通過模仿學會Python爬蟲(一):零基礎上手

    好家伙,爬蟲來了 爬蟲,這玩意,不會怎么辦, 誒,先抄一份作業回來 1.別人的爬蟲 Python爬蟲史上超詳細講解(零基礎入門,老年人都看的懂)_ChenBinBini的博客-CSDN博客 # -*- codeing = utf-8 -*- from bs4 import BeautifulSoup ......

    uj5u.com 2023-06-18 07:38:11 more
  • Python潮流周刊#7:我討厭用 asyncio

    你好,我是貓哥。這里記錄每周值得分享的 Python 及通用技術內容,部分為英文,已在小標題注明。(標題取自其中一則分享,不代表全部內容都是該主題,特此宣告。) 首發于我的博客:[https://pythoncat.top/posts/2023-06-17-weekly7](https://pyth ......

    uj5u.com 2023-06-18 07:32:25 more
  • Django學習筆記

    ## 1.常用命令 `創建專案:django-admin startproject 專案名` `創建APP(進入工程目錄):python manage.py startapp 網站名` `創建庫表(進入工程目錄):python manage.py makemigrations` `執行庫表建立(進入 ......

    uj5u.com 2023-06-18 07:32:06 more
  • 09. centos使用docker方式安裝mysql

    ## 一、創建宿主機物理路徑 新建/mydata/mysql/data、log和conf三個檔案夾 ```bash mkdir -p /mnt/mysql/log mkdir -p /mnt/mysql/data mkdir -p /mnt/mysql/config ``` 或者 ```bash m ......

    uj5u.com 2023-06-18 07:31:43 more
  • Java 注釋及Dos命令

    # Java 注釋、絕對路徑、相對路徑、基本Dos命令 # 1. Java的三種注釋方式 ## 注釋能增加代碼的可讀性,習慣寫注釋能提升我們撰寫代碼的能力 > ### 單行注釋:用//注釋一些代碼提示 > > ### 多行注釋:以/*為開頭 以 */為結束 > > ### 檔案注釋:/* > > # ......

    uj5u.com 2023-06-18 07:30:01 more
  • Nginx 學習筆記

    ## 概述 Nginx 是一個高性能的 HTTP 和反向代理服務器,特點是占用記憶體少,并發能力強 #### 1. 正向代理 如果把局域網外的 Internet 想象成一個巨大的資源庫,則局域網中的客戶端要訪問 Internet,需要通過代理服務器來訪問,這種訪問就稱為正向代理 ![](https:/ ......

    uj5u.com 2023-06-18 07:24:46 more
  • C++面試八股文:什么是左值,什么是右值?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第16面: > 面試官:什么是左值,什么是右值? > > 二師兄:簡單來說,左值就是可以使用`&`符號取地址的值,而右值一般不可以使用`&`符號取地址。 ```c++ int a = 42; //a是左值,可以&a int* p = &a; int* ......

    uj5u.com 2023-06-17 07:27:40 more