🦫 Π‘Π°ΠΌΠΎΡƒΡ‡ΠΈΡ‚Π΅Π»ΡŒ ΠΏΠΎ Go для Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΡ…. Π§Π°ΡΡ‚ΡŒ 11. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок. Паника. ВосстановлСниС. Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

Рассмотрим устройство ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ° ошибок Π² Go ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈΡ… ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, познакомимся с функциями ΠΏΠ°Π½ΠΈΠΊΠΈ ΠΈ восстановлСния, Π° Ρ‚Π°ΠΊΠΆΠ΅ научимся Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ состоянии ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… Π»ΠΎΠ³Π΅Ρ€ΠΎΠ².

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ошибок Π² Go

Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ популярных языков, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ JavaScript, Python, Π‘++, Π² Go принято Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ с ошибками Ρ‡Π΅Ρ€Π΅Π· ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° error. ΠŸΡ€ΠΈ этом Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ (nil) Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ошибки Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ»ΠΎ. Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ позволяСт наглядно Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠ΅ ошибки, ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΈΡ… с использованиСм ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ… синтаксичСских конструкций.

Π’ΠΈΠΏ error прСдставляСт собой интСрфСйс с СдинствСнным ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ Error, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠΌ тСкстовоС описаниС ошибки:

type error interface {
    Error() string
}

Π˜Π΄ΠΈΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΠΈΠΌ способом ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибок являСтся ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ значСния с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ условного ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° if. ΠŸΡ€ΠΎΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ это Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ strconv.Atoi ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° strconv со ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ сигнатурой: func Atoi(s string) (int, error) МоТСм Π²ΠΈΠ΄Π΅Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π΄Π²Π° значСния – Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ прСобразования строки Π² число ΠΈ ΠΎΡˆΠΈΠ±ΠΊΡƒ:

res, err := strconv.Atoi("123a")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(res)

Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ строку, ΡΠΎΡΡ‚ΠΎΡΡ‰ΡƒΡŽ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ· Ρ†ΠΈΡ„Ρ€, Ρ‚ΠΎ Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ выполнСния ΠΊΠΎΠ΄Π° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ err Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΎΡ‚ nil, ΠΈ Π² консоль Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ описаниС возникшСй ошибки: strconv.Atoi: parsing "123a": invalid syntax.

БозданиС ошибок

Для создания ошибок с ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΌ тСкстом ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ errors.New() ΠΈ fmt.Errorf():

// errors.New() ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ тСкстовоС описаниС ошибки
if err != nil {
	return errors.New("описаниС ошибки")
}

// fmt.Errorf() позволяСт ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π² описаниС ошибки
param := 0
if err != nil {
	return fmt.Errorf("описаниС ошибки c ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ Ρ‚ΠΈΠΏΠ° int: %d", param)
}

Часто Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ создания ΠΈΠ½Π΄ΠΈΠ²ΠΈΠ΄ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² ошибок для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… сбоСв Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅. Для этого Π½ΡƒΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρƒ этих Ρ‚ΠΈΠΏΠΎΠ² интСрфСйс error посрСдством создания ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Error():

type errorConst string // Ρ‚ΠΈΠΏ константной ошибки

const ErrConst errorConst = "stack overflow"

func (e errorConst) Error() string {
	return string(e)
}

Π’ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… случаях ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π² описаниС ошибки, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ Π½ΠΎΠΌΠ΅Ρ€Π° строк, названия ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ², адрСса ΠΏΠΎΡ€Ρ‚ΠΎΠ² ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. Для этих Ρ†Π΅Π»Π΅ΠΉ стоит ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ структуры, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ Error() интСрфСйса error.

Π’ качСствС ΠΈΠ»Π»ΡŽΡΡ‚Ρ€Π°Ρ†ΠΈΠΈ этого ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ привСсти Ρ‚ΠΈΠΏ ParseError ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° net стандартной Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

// ParseError β€” это Ρ‚ΠΈΠΏ ошибки синтаксичСского Π°Π½Π°Π»ΠΈΠ·Π° сСтСвых адрСсов.
type ParseError struct {
	// Type β€” это Ρ‚ΠΈΠΏ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΠΎΠΉ строки, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€
	// "IP address", "CIDR address".
	Type string

	// Text β€” это нСвСрная тСкстовая строка.
	Text string
}

func (e *ParseError) Error() string {
	return "invalid " + e.Type + ": " + e.Text 
}

Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ error Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ СдинствСнного ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Error(), Π½ΠΎ для ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… случаСв Π±Ρ‹Π²Π°Π΅Ρ‚ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ net стандартной Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ошибок ΠΈΠΌΠ΅ΡŽΡ‚ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ интСрфСйсом net.Error:

package net

type Error interface {
    error
    Timeout() bool   // Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ошибки
    Temporary() bool // постоянныС ошибки
}

Π’ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Ρ… ситуациях для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибки ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ type assertion, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΅Ρ‘ Ρ‚ΠΈΠΏ. ΠŸΡ€ΠΎΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ это Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ Π±Π»ΠΎΠΊΠ΅ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ провСряСт постоянной ΠΈΠ»ΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ являСтся возникшая ошибка ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ. Π’ ΠΏΠ΅Ρ€Π²ΠΎΠΌ случаС установим Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ, послС ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅, Π° Π²ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌ – Π²Ρ‹Π²Π΅Π΄Π΅ΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

// ΠœΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ type assertion для привСдСния ошибки ΠΊ Ρ‚ΠΈΠΏΡƒ net.Error
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
    time.Sleep(1e9)
    continue
}

// Если ошибка врСмСнная (Timeout), Ρ‚ΠΎ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π΅Ρ‘ ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
πŸ‘¨β€πŸ’» Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Go Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Go Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°Β»
πŸŽ“ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Go для собСса
ΠŸΠΎΠ΄Ρ‚ΡΠ½ΡƒΡ‚ΡŒ свои знания ΠΏΠΎ Go Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Go для собСса»
🧩 Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π·Π°Π΄Π°Ρ‡ ΠΏΠΎ Go
Π˜Π½Ρ‚Π΅Ρ€Π΅ΡΠ½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΏΠΎ Go для ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π·Π°Π΄Π°Ρ‡ ΠΏΠΎ GoΒ»

ΠŸΡ€Π°Π²ΠΈΠ»Π° имСнования ошибок

БущСствуСт нСсколько соглашСний ΠΏΠΎ имСнованию ошибок, принятых Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ ΠΈ сообщСством Go. Π‘Π»Π΅Π΄ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠΌ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΠΎΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π΅Π΄ΠΈΠ½ΠΎΠΎΠ±Ρ€Π°Π·ΠΈΠ΅.

Π‘Π°Π·ΠΎΠ²ΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ имСнования ошибок Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ error-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ΡΡ с err ΠΈΠ»ΠΈ Err, Π° error-Ρ‚ΠΈΠΏΡ‹ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°ΡŽΡ‚ΡΡ Π½Π° Error:

var ErrProhibitedBehavior = errors.New("packagename: prohibited behaviour")

type SomeError struct {
	Line, Column int
}

Π’Π°ΠΊΠΆΠ΅ стоит Π·Π°ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ строка описания ошибки Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒΡΡ с большой Π±ΡƒΠΊΠ²Ρ‹.

Π’ описании ошибок слСдуСт ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎΠ΅ мСстополоТСниС: Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π°, Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ»ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Π² ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ expression тСкстовоС описаниС ошибки Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ матСматичСского выраТСния ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ: β€œexpression: invalid format”.

Panic

Panic (ΠΏΠ°Π½ΠΈΠΊΠ°) – это встроСнная функция, которая останавливаСт ΠΏΠΎΡ‚ΠΎΠΊ выполнСния ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ запускаСт ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ ΠΏΠ°Π½ΠΈΠΊΠΈ. Он ΠΏΠΎΡ…ΠΎΠΆ Π½Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π² C++ ΠΈ Java, ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π²Ρ‹Π·Π²Π°Π½ ошибками runtime, Ρ‚Π°ΠΊΠΈΠΌΠΈ ΠΊΠ°ΠΊ Π²Ρ‹Ρ…ΠΎΠ΄ Π·Π° Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ массива, Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π½Π° ноль, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ³ΠΎ слова panic.

Рассмотрим ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ ΠΏΠ°Π½ΠΈΠΊΠΈ Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅: создадим Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ DivideNums для дСлСния вСщСствСнных чисСл. Если Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ, Ρ‚ΠΎ Π²Ρ‹Π·ΠΎΠ²Π΅ΠΌ panic с тСкстом "Division by zero", ΠΈΠ½Π°Ρ‡Π΅ – Π²Π΅Ρ€Π½Π΅ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ дСлСния:

func DivideNums(a, b float32) float32 {
	if b == 0.0 {
		panic("Division by zero")
	}
	return a / b
}

func main() {
	fmt.Println(DivideNums(1, 0)) // panic
	fmt.Println(DivideNums(1, 2)) // Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ Π½Π΅ выполнится
}

Π’ случаС Π²Ρ‹Π·ΠΎΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ с Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ 1 ΠΈ 0 Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ‚ ΠΏΠ°Π½ΠΈΠΊΠ°, Π½Π° экран Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:

panic: Division by zero

goroutine 1 [running]:
main.DivideNums(...)
        /path/to/folder/main.go:7
main.main()
        /path/to/folder/main.go.go:13 +0x25
exit status 2

Π Π°Π·Π±Π΅Ρ€Π΅ΠΌ процСсс ΠΏΠ°Π½ΠΈΠΊΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅. Когда нСкоторая функция func Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ panic, Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ происходит ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:

  1. ΠžΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Π΅Ρ‚ΡΡ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ func.
  2. Π’Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ всС Π΅Ρ‘ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ defer-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.
  3. Π—Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ defer-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, связанныС с func Π²ΠΏΠ»ΠΎΡ‚ΡŒ Π΄ΠΎ Π²Π΅Ρ€Ρ…Π½Π΅Π³ΠΎ уровня Π² исполняСмой Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π΅.
  4. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° panic.

Паника тСсно связана с Π²Π°ΠΆΠ½ΠΎΠΉ ΡΡƒΡ‰Π½ΠΎΡΡ‚ΡŒΡŽ Go – Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π°ΠΌΠΈ. Они ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ собой нСзависимыС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‰ΠΈΠ΅ΡΡ ΠΊΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈ Ρ‚ΠΎΠΌ ΠΆΠ΅ адрСсном пространствС, ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π°Π½Π°Π»ΠΎΠ³ΠΎΠΌ ΠΊΠΎΡ€ΡƒΡ‚ΠΈΠ½ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… языках. Π“ΠΎΡ€ΡƒΡ‚ΠΈΠ½Ρ‹ ΠΈΠΌΠ΅ΡŽΡ‚ динамичСский стСк ΠΈ ΡƒΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠΎΠΌ Go. Π“Π»Π°Π²Π½ΠΎΠΉ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½ΠΎΠΉ являСтся функция main, Π΅Ρ‘ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΡŽ Ρ€Π°Π±ΠΎΡ‚Ρ‹ всСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

Π‘ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ рассмотрСны Π² ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… частях, Π² контСкстС Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ достаточно лишь ΠΎΠ±Ρ‰Π΅Π³ΠΎ понимания. Для ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠ³ΠΎ погруТСния Π² Ρ‚Π΅ΠΌΡƒ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π» Β«Π“ΠΎΡ€ΡƒΡ‚ΠΈΠ½Ρ‹: Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΠΈ ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚Β».

Recovery

Π’ условиях ΠΏΡ€ΠΎΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΎΠΉ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ часто Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΏΠ°Π½ΠΈΠΊΡƒ ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΊ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎΠΌΡƒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡŽ, ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‚ΠΈΠ² Π΅Π³ΠΎ Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎΠ΅ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅. Для этих Ρ†Π΅Π»Π΅ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ восстановлСния (recovery), Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‰ΠΈΠΉΡΡ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ встроСнной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ recover. Она позволяСт Π²ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ Π½Π°Π΄ ΠΏΠ°Π½ΠΈΠΊΡƒΡŽΡ‰Π΅ΠΉ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½ΠΎΠΉ ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π²Ρ‹Π·Π²Π°Π½Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ defer-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ.

Recover ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² Ρ‚Π΅Ρ… случаях, ΠΊΠΎΠ³Π΄Π° ΠΏΠ°Π½ΠΈΠΊΠ° Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° привСсти ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ всСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. НапримСр, ошибка Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈΠ· клиСнтских ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ Π²Π΅Π±-сСрвСра Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° привСсти ΠΊ сбою всСго сСрвСрного прилоТСния. Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ recover Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ошибки Π² стСкС рСкурсивных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ ΠΈ Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ возникшиС Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ ΠΏΠ°Π½ΠΈΠΊΠΈ.

Ѐункция recover Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ nil, ΠΊΠΎΠ³Π΄Π° Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π° Π½Π΅ ΠΏΠ°Π½ΠΈΠΊΡƒΠ΅Ρ‚ ΠΈΠ»ΠΈ recover Π½Π΅ Π±Ρ‹Π» Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π²Ρ‹Π·Π²Π°Π½ Π² defer-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π’ ΠΈΠ½Ρ‹Ρ… случаях возвращаСтся Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎΠ΅ ΠΎΡ‚ nil. Если какая-Π»ΠΈΠ±ΠΎ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π° Π·Π°ΠΏΠ°Π½ΠΈΠΊΠΎΠ²Π°Π»Π°, Ρ‚ΠΎ Π²Ρ‹Π·ΠΎΠ² recovery досрочно остановит раскручиваниС стСка, Π²Π΅Ρ€Π½Π΅Ρ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ Π² panic, ΠΈ Π²ΠΎΠ·ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ дальнСйшСС Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

ΠŸΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с recover слСдуСт ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ Π΄Π²Π° Π²Π°ΠΆΠ½Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ»Π°:

  1. recover() ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ defer-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ
  2. recover() Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ‚ΠΎΠΉ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π΅, Π³Π΄Π΅ Π±Ρ‹Π»Π° Π²Ρ‹Π·Π²Π°Π½Π° ΠΏΠ°Π½ΠΈΠΊΠ°

Рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ recover Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ с Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ DivideNums. На этот Ρ€Π°Π· запустим ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ восстановлСния послС возникновСния ΠΏΠ°Π½ΠΈΠΊΠΈ β€œDivision by zero”:

func DivideNums(a, b float32) float32 {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovery:", r)
		}
	}()

	if b == 0.0 {
		panic("Division by zero")
	}

	return a / b
}

func main() {
	fmt.Println(DivideNums(10, 0))
	fmt.Println(DivideNums(10, 5))
}

ПослС выполнСния ΠΊΠΎΠ΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²Ρ‹Π²ΠΎΠ΄:

Recovery: Division by zero
0
2

Π”Π°Π²Π°ΠΉΡ‚Π΅ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρƒ написанной ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ΠŸΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² (10, 0) Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ DivideNums Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΏΠ°Π½ΠΈΠΊΠ°, которая запускаСт ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² defer. Он провСряСт Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠ΅ ΠΏΠ°Π½ΠΈΠΊΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ recover(): Ссли Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π½Π΅ Ρ€Π°Π²Π½ΠΎ nil, Ρ‚ΠΎ ΠΏΠ°Π½ΠΈΠΊΠ° обрабатываСтся, Π½Π° экран выводится сообщСниС β€œRecovery: Division by zero”, послС Ρ‡Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° возвращаСтся ΠΊ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎΠΌΡƒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡŽ. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ΠΏΠ°Π½ΠΈΠΊΠ°, функция DivideNums() Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ΡΡ, возвращая Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ для float32, Ρ€Π°Π²Π½ΠΎΠ΅ 0. Π”Π°Π»Π΅Π΅ слСдуСт Π²Ρ‹Π·ΠΎΠ² DivideNums с двумя Π½Π΅Π½ΡƒΠ»Π΅Π²Ρ‹ΠΌΠΈ числами, поэтому Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ возвращаСтся ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ (2), ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ выводится Π½Π° экран.

Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

Π’ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΈΠ΅ Ρ‚Π΅ΠΌΡ‹ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибок ΠΈΠ·ΡƒΡ‡ΠΈΠΌ эффСктивный инструмСнт для ΠΈΡ… своСврСмСнного отслСТивания – Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅.

Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ – это процСсс записи ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎΠ±ΠΎ всСх событиях, происходящих Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅. Как ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π·Π°ΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ Π² ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹, Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹Π΅ Π»ΠΎΠ³Π°ΠΌΠΈ. Они содСрТат сообщСния ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…, прСдупрСТдСния, Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ состояниС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ дСйствия ΠΈ Π΄Ρ€ΡƒΠ³ΡƒΡŽ Π²Π°ΠΆΠ½ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ.

Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ ΠΏΠΎ ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π°ΠΌ:

  1. ΠžΡ‚Π»Π°Π΄ΠΊΠ° ΠΈ диагностика ошибок. Π›ΠΎΠ³ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ошибки, Π²ΠΎΠ·Π½ΠΈΠΊΠ°ΡŽΡ‰ΠΈΠ΅ Π² процСссС выполнСния ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ЗаписанныС Π΄Π°Π½Π½Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π² Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ ΠΈ выявлСнии ΠΈΡ… ΠΏΡ€ΠΈΡ‡ΠΈΠ½.
  2. ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ ΠΈ Π°Π½Π°Π»ΠΈΠ· ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ. Π’ Π»ΠΎΠ³Π°Ρ… ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒΡΡ информация ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ ΠΈ объСмС потрСбляСмых рСсурсов. Π­Ρ‚ΠΎ позволяСт ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ прилоТСния ΠΈ Π²Ρ‹ΡΠ²Π»ΡΡ‚ΡŒ мСста, Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ.
  3. Аналитика ΠΈ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ. Π›ΠΎΠ³ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ для сбора Π΄Π°Π½Π½Ρ‹Ρ… ΠΎ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ для Π°Π½Π°Π»ΠΈΠ·Π° ΠΈΡ… активности, ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡Ρ‚Π΅Π½ΠΈΠΉ. Вакая информация Π½ΡƒΠΆΠ½Π° для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΎΠΏΡ‹Ρ‚Π° ΠΈ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.
  4. Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½Π°Ρ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ. Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π²Π°ΠΆΠ½ΡƒΡŽ Ρ€ΠΎΠ»ΡŒ Π² обСспСчСнии бСзопасности ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, позволяя ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ нСсанкционированный доступ, ΡƒΡ‚Π΅Ρ‡ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ ΡƒΠ³Ρ€ΠΎΠ·Ρ‹.

Π”Π°Π»Π΅Π΅ рассмотрим Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ для логирования Π² Go: log, logrus ΠΈ slog.

Π‘Ρ‚Π°Π½Π΄Π°Ρ€Ρ‚Π½Ρ‹ΠΉ ΠΏΠ°ΠΊΠ΅Ρ‚ log

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ языка прСдусмотрСли стандартный ΠΏΠ°ΠΊΠ΅Ρ‚ log для простого логирования ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ. Он ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ прСдоставляСт лишь Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ инструмСнтов для частых Π·Π°Π΄Π°Ρ‡.

Рассмотрим основныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π° log:

  1. Print, Println, Printf – Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΊΠ°ΠΊ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° fmt.
  2. Panic, Panicf, Panicln – Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΊΠ°ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Print, Π½ΠΎ послС Π²Ρ‹Π²ΠΎΠ΄Π° тСкста Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ panic().
  3. Fatal, Fatalln, Fatalf – Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΊΠ°ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Print, Π½ΠΎ послС Π²Ρ‹Π²ΠΎΠ΄Π° тСкста Π·Π°Π²Π΅Ρ€ΡˆΠ°ΡŽΡ‚ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ ΠΏΡƒΡ‚Π΅ΠΌ Π²Ρ‹Π·ΠΎΠ²Π° os.Exit(1).
  4. SetFlags – устанавливаСт Ρ„Π»Π°Π³ΠΈ для форматирования. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Ρ„Π»Π°Π³ Lmicroseconds Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ микросСкунды ΠΊΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Lshortfile ΡƒΠΊΠ°ΠΆΠ΅Ρ‚ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ, ΠΎΡ‚ΠΊΡƒΠ΄Π° Π±Ρ‹Π»ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ сообщСниС.
  5. SetOutput – ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π²Ρ‹Π²ΠΎΠ΄Π° Π»ΠΎΠ³ΠΎΠ². МоТно ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ любой ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‰ΠΈΠΉ интСрфСйс io.Writer: Ρ„Π°ΠΉΠ», Π±ΡƒΡ„Π΅Ρ€, сСтСвоС соСдинСниС ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅.
  6. SetPrefix – устанавливаСт прСфикс для Π»ΠΎΠ³ΠΎΠ².

ΠŸΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ этих Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π² ΠΊΠΎΠ΄Π΅:

func main() {
	log.Print("сообщСниС ΠΎΡ‚ log.Print")

	log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
	log.Println("сообщСниС с Ρ„Π»Π°Π³Π°ΠΌΠΈ")

	var buf bytes.Buffer // объявлСниС Π±ΡƒΡ„Π΅Ρ€Π°
	bufLogger := log.New(&buf, "buf:", log.LstdFlags)
	bufLogger.Print("сообщСниС Π² Π±ΡƒΡ„Π΅Ρ€Π΅ buf")

	bufLogger.SetPrefix("bufPrefix:")
	bufLogger.Print("сообщСниС Π² Π±ΡƒΡ„Π΅Ρ€Π΅ buf с прСфиксом bufPrefix:")
	fmt.Print(buf.String())

	// ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π° "logfile.log" для Π»ΠΎΠ³ΠΎΠ²
	// Ссли Ρ„Π°ΠΉΠ»Π° Π½Π΅Ρ‚, Ρ‚ΠΎ ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ создан
	file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err == nil {
		log.SetOutput(file) // ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π²Ρ‹Π²ΠΎΠ΄Π° Π»ΠΎΠ³ΠΎΠ² Π² Ρ„Π°ΠΉΠ» logfile.log
	} else {
		log.Panic("Ошибка открытия Ρ„Π°ΠΉΠ»Π° Π»ΠΎΠ³ΠΎΠ²:", err)
	}
	defer file.Close() // ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ΅ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
}

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ выполнСния ΠΊΠΎΠ΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π·Π»ΠΈΡ‡Π°Ρ‚ΡŒΡΡ Π² зависимости ΠΎΡ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ запуска:

2024/03/14 11:52:16 сообщСниС ΠΎΡ‚ log.Print
2024/03/14 11:52:16.222089 main.go:14: сообщСниС с Ρ„Π»Π°Π³Π°ΠΌΠΈ
buf:2024/03/14 11:52:16 сообщСниС Π² Π±ΡƒΡ„Π΅Ρ€Π΅ buf
bufPrefix:2024/03/14 11:52:16 сообщСниС Π² Π±ΡƒΡ„Π΅Ρ€Π΅ buf с прСфиксом bufPrefix:

ΠŸΠ°ΠΊΠ΅Ρ‚ logrus

ΠŸΠ°ΠΊΠ΅Ρ‚ logrus Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π° log, прСдоставляя ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Π΅ возмоТности: Π·Π°Π΄Π°Π½ΠΈΠ΅ ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ логирования, настройка Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° Π²Ρ‹Π²ΠΎΠ΄Π°, внСсСниС Π² сообщСния Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅.

Logrus прСдоставляСт 7 ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ логирования, упорядочСнных ΠΏΠΎ Π²ΠΎΠ·Ρ€Π°ΡΡ‚Π°Π½ΠΈΡŽ значимости Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅: Trace, Debug, Info, Warning, Error, Fatal and Panic. Π£Ρ€ΠΎΠ²Π΅Π½ΡŒ задаСтся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ SetLevel. НиТС прСдставлСн ΠΊΠΎΠ΄, Π΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ всСх ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ логирования ΠΈ ΠΈΡ… Π½Π°Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:

func main() {
	logrus.SetLevel(logrus.TraceLevel)
	logrus.Trace("Для отслСТивания ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ")
	logrus.Debug("Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ")
	logrus.Info("Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ дСйствиях ΠΈ состоянии ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹")
	logrus.Warn("Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ, Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‰Π°Ρ внимания")
	logrus.Error("Ошибка, которая Π½Π΅ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹")
	logrus.Fatal("Ошибка, Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ слуТбы ΠΈΠ»ΠΈ прилоТСния")
	logrus.Panic("Ошибка, Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ panic")
}

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½Ρ‹ Ρ†Π²Π΅Ρ‚Π½Ρ‹Π΅ прСфиксы ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ логирования с ΠΈΡ… описаниСм:

TRAC[0000] Для отслСТивания ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ     
DEBU[0000] Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ                       
INFO[0000] Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ дСйствиях ΠΈ состоянии ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ 
WARN[0000] Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ, Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‰Π°Ρ внимания               
ERRO[0000] Ошибка, которая Π½Π΅ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ 
FATA[0000] Ошибка, Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ слуТбы ΠΈΠ»ΠΈ прилоТСния 

ΠžΡ‚ΠΌΠ΅Ρ‚ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ссли ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ logrus.SetLevel(logrus.InfoLevel) вмСсто logrus.SetLevel(logrus.TraceLevel), Ρ‚ΠΎ сообщСния ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ Π½ΠΈΠΆΠ΅ Info, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Trace ΠΈ Debug, Π²Ρ‹Π²Π΅Π΄Π΅Π½Ρ‹ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚.

Logrus позволяСт Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊ Π΄Π°Π½Π½Ρ‹ΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ описаниС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ logrus.WithFields:

func main() {
	// Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ запуска TCP-сСрвСра Π½Π° ΠΏΠΎΡ€Ρ‚Ρƒ 8080
	logrus.WithFields(logrus.Fields{
		"network":  "tcp",
		"address:": ":8080",
	}).Info("Starting server...")
}

ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄ Π²Ρ‹Π²Π΅Π΄Π΅Ρ‚ сообщСниС ΠΎ стартС сСрвСра с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ Π΄Π²ΡƒΡ… Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΎΠ»Π΅ΠΉ: адрСса (:8080) ΠΈ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π° (tcp):

INFO[0000] Starting server...   address:=":8080" network=tcp

Для установки Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° Π²Ρ‹Π²ΠΎΠ΄Π° Π»ΠΎΠ³ΠΎΠ² ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ функция logrus.SetFormatter

func main() {
	logrus.SetFormatter(&logrus.JSONFormatter{}) // JSON Ρ„ΠΎΡ€ΠΌΠ°Ρ‚
	logrus.Info("JSONFormatter INFO message")
	
	logrus.SetFormatter(&logrus.TextFormatter{ // настраиваСмый тСкстовый Ρ„ΠΎΡ€ΠΌΠ°Ρ‚
		DisableColors: true, // ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚ΠΎΠ²
		FullTimestamp: true, // Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠΎΠ»Π½ΠΎΠΉ Π΄Π°Ρ‚Ρ‹
	})
	logrus.Info("TextFormatter INFO message")
}

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ выполнСния ΠΊΠΎΠ΄Π° Π½Π° ΠΏΠ΅Ρ€Π²ΠΎΠΉ строкС ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ сообщСниС Π² JSON Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅, Π° Π½Π° Π²Ρ‚ΠΎΡ€ΠΎΠΌ – Π² тСкстовом с Π·Π°Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ:

{"level":"info","msg":"JSONFormatter INFO message","time":"2024-03-14T17:23:45+03:00"}
time="2024-03-14T17:23:45+03:00" level=info msg="TextFormatter INFO message"

ΠŸΠ°ΠΊΠ΅Ρ‚ slog

ΠŸΠ°ΠΊΠ΅Ρ‚ slog Π±Ρ‹Π» ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ сообщСством энтузиастов ΠΊΠ°ΠΊ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° log, послС Ρ‡Π΅Π³ΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠ°Π½ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ ΠΈ Π²Ρ‹ΠΏΡƒΡ‰Π΅Π½ Π² вСрсии Go v1.21 ΠΏΠΎ адрСсу log/slog. Он ΠΎΠ±Π»Π°Π΄Π°Π΅Ρ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ с log ΠΈ заимствуСт ΠΈΠ· Π½Π΅Π³ΠΎ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π½ΠΎ ΠΎΠ±Π»Π°Π΄Π°Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΠΎΠΌ ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎΠΉ настройки.

Π’ ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ slog присутствуСт 4 основных уровня логирования, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΡƒΡŽΡ‚ΡΡ Ρ†Π΅Π»Ρ‹ΠΌΠΈ числами с ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΠΌ Π² 4: Debug (-4), Info (0), Warn (4), Error (8). Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ прСдоставляСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ свои ΡƒΡ€ΠΎΠ²Π½ΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‡Π΅Ρ‚Ρ‹Ρ€ΡŒΠΌΡ стандартными. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ логирования ΠΌΠ΅ΠΆΠ΄Ρƒ Debug ΠΈ Info с Ρ†Π΅Π»Ρ‹ΠΌΠΈ значСниями Π² ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π΅ (-4;0).

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π° slog схоТи с рассмотрСнными Ρ€Π°Π½Π΅Π΅. Для сравнСния Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ ΠΈΡ… Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅:

func main() {
	slogger := slog.New(slog.NewTextHandler(os.Stdout, nil)) // созданиС Π»ΠΎΠ³Π΅Ρ€Π°
	slog.SetDefault(slogger) // установка Π»ΠΎΠ³Π΅Ρ€Π° ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ

	slogger.Debug("Debug message")
	slogger.Info("Info message")
	slogger.Warn("Warn message")
	slogger.Error("Error message")

	// Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚ старого Π»ΠΎΠ³Π΅Ρ€Π° ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° log Π±ΡƒΠ΄Π΅Ρ‚
	// ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΎ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Π½ΠΎΠ²ΠΎΠ³ΠΎ Π»ΠΎΠ³Π΅Ρ€Π° ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° slog
	log.Print("Message from old logger")

	// Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ с Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°ΠΌΠΈ Π² Π²ΠΈΠ΄Π΅ ΠΏΠ°Ρ€ "ΠΊΠ»ΡŽΡ‡-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅"
	slogger.Info(
		"Server started",
		"port", ":8080",
		"network", "tcp",
	)
}

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ выполнСния ΠΊΠΎΠ΄Π° Π² консоль Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:

time=2024-03-14T18:52:08.437+03:00 level=INFO msg="Info message"
time=2024-03-14T18:52:08.437+03:00 level=WARN msg="Warn message"
time=2024-03-14T18:52:08.437+03:00 level=ERROR msg="Error message"
time=2024-03-14T18:52:08.437+03:00 level=INFO msg="Message from old logger"
time=2024-03-14T18:52:08.437+03:00 level=INFO msg="Server started" port=:8080 network=tcp

Бинтаксис Ρ‡Π΅Ρ€Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎΡΡ значСния ΠΊΠ»ΡŽΡ‡Π΅ΠΉ для Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ² ΡƒΠ΄ΠΎΠ±Π΅Π½, Π½ΠΎ для часто выполняСмых ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ эффСктивным ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏ Attr с ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ LogAttrs. Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ памяти ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Ρ‚ΠΈΠΏΠΎΠ² ΠΏΡ€ΠΈ ΡƒΠΊΠ°Π·Π°Π½ΠΈΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ². Учитывая это, Π·Π°ΠΌΠ΅Π½ΠΈΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ с Π²Ρ‹Π²ΠΎΠ΄ΠΎΠΌ сообщСния β€œServer started” Π½Π° Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΉ с использованиСм LogAttrs:

func main() {
	slogger := slog.New(slog.NewTextHandler(os.Stdout, nil)) // созданиС Π»ΠΎΠ³Π΅Ρ€Π°

	// Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ с Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°ΠΌΠΈ Π² Π²ΠΈΠ΄Π΅ ΠΏΠ°Ρ€ "ΠΊΠ»ΡŽΡ‡-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅"
	slogger.LogAttrs(
		context.Background(),
		slog.LevelInfo,
		"Server started",
		slog.String("port", ":8080"),
		slog.String("network", "tcp"),
	)
}

Π’ консоль Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ сообщСниС:

time=2024-03-14T19:39:59.247+03:00 level=INFO msg="Server started" port=:8080 network=tcp

Настройка ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ², Π²ΠΊΠ»ΡŽΡ‡Π°Ρ TextHandler ΠΈ JSONHandler, производится с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ‚ΠΈΠΏΠ° HandlerOptions:

func main() {
	opts := &slog.HandlerOptions{
		AddSource: true,           // ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ ΠΏΡƒΡ‚ΠΈ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ
		Level:     slog.LevelInfo, // Π·Π°Π΄Π°Π½ΠΈΠ΅ минимального уровня
	}
	slogger := slog.New(slog.NewTextHandler(os.Stdout, opts)) // созданиС Π»ΠΎΠ³Π΅Ρ€Π°

	slogger.Debug("Debug message")
	slogger.Info("Info message")
}

ПослС выполнСния ΠΊΠΎΠ΄Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ сообщСниС уровня Info с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΏΡƒΡ‚ΠΈ ΠΊ исполняСмому Ρ„Π°ΠΉΠ»Ρƒ:

time=2024-03-14T19:24:38.685+03:00 level=INFO source=/home/herman/myfolder/solve/main.go:16 msg="Info message"

ПодвСдСм ΠΈΡ‚ΠΎΠ³ΠΈ

Π’ этой части самоучитСля ΠΌΡ‹ Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠ»ΠΈ нашС прСдставлСниС ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…, ΡƒΠ·Π½Π°Π»ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈΡ… ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ познакомились с ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ°ΠΌΠΈ ΠΏΠ°Π½ΠΈΠΊΠΈ ΠΈ восстановлСния. Π’ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌ Π±Π»ΠΎΠΊΠ΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ Π±Ρ‹Π»ΠΎ рассмотрСно Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² Go с использованиСм Ρ‚Ρ€Π΅Ρ… Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ²: log, logrus ΠΈ slog.

Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ части погрузимся Π² ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΡƒ ΠΎΠ±ΠΎΠ±Ρ‰Π΅Π½Π½ΠΎΠ³ΠΎ программирования ΠΈ ΠΈΠ·ΡƒΡ‡ΠΈΠΌ Π΄ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠΈ, Π° Π² ΠΊΠΎΠ½Ρ†Π΅ Π·Π°ΠΊΡ€Π΅ΠΏΠΈΠΌ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π» Π½Π° интСрСсных Π·Π°Π΄Π°Ρ‡Π°Ρ….

***

Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅ самоучитСля

  1. ΠžΡΠΎΠ±Π΅Π½Π½ΠΎΡΡ‚ΠΈ ΠΈ сфСра примСнСния Go, установка, настройка
  2. РСсурсы для изучСния Go с нуля
  3. ΠžΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΡ ΠΊΠΎΠ΄Π°. ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹, ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹, ΠΌΠΎΠ΄ΡƒΠ»ΠΈ. Π’Π²ΠΎΠ΄-Π²Ρ‹Π²ΠΎΠ΄ тСкста.
  4. ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅. Π’ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΠΈΡ… прСобразования. ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹
  5. УсловныС конструкции if-else ΠΈ switch-case. Π¦ΠΈΠΊΠ» for. Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΈ бСсконСчныС Ρ†ΠΈΠΊΠ»Ρ‹
  6. Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹. ΠžΠ±Π»Π°ΡΡ‚ΠΈ видимости. РСкурсия. Defer
  7. ΠœΠ°ΡΡΠΈΠ²Ρ‹ ΠΈ слайсы. Append ΠΈ сopy. ΠŸΠ°ΠΊΠ΅Ρ‚ slices
  8. Π‘Ρ‚Ρ€ΠΎΠΊΠΈ, Ρ€ΡƒΠ½Ρ‹, Π±Π°ΠΉΡ‚Ρ‹. ΠŸΠ°ΠΊΠ΅Ρ‚ strings. Π₯Сш-Ρ‚Π°Π±Π»ΠΈΡ†Π° (map)
  9. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡΡ‹. Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ. ΠžΡΠ½ΠΎΠ²Ρ‹ ООП
  10. НаслСдованиС, абстракция, ΠΏΠΎΠ»ΠΈΠΌΠΎΡ€Ρ„ΠΈΠ·ΠΌ, инкапсуляция
  11. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок. Паника. ВосстановлСниС. Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
  12. ΠžΠ±ΠΎΠ±Ρ‰Π΅Π½Π½ΠΎΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅. Π”ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠΈ
  13. Π Π°Π±ΠΎΡ‚Π° с Π΄Π°Ρ‚ΠΎΠΉ ΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ. ΠŸΠ°ΠΊΠ΅Ρ‚ time
  14. Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡΡ‹ Π²Π²ΠΎΠ΄Π°-Π²Ρ‹Π²ΠΎΠ΄Π°. БуфСризация. Π Π°Π±ΠΎΡ‚Π° с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ. ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹ io, bufio, os
  15. ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ. Π“ΠΎΡ€ΡƒΡ‚ΠΈΠ½Ρ‹. ΠšΠ°Π½Π°Π»Ρ‹
  16. ВСстированиС ΠΊΠΎΠ΄Π° ΠΈ Π΅Π³ΠΎ Π²ΠΈΠ΄Ρ‹. Table-driven ΠΏΠΎΠ΄Ρ…ΠΎΠ΄. ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½Ρ‹Π΅ тСсты
  17. ΠžΡΠ½ΠΎΠ²Ρ‹ сСтСвого программирования. Π‘Ρ‚Π΅ΠΊ TCP/IP. Π‘ΠΎΠΊΠ΅Ρ‚Ρ‹. ΠŸΠ°ΠΊΠ΅Ρ‚ net

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
04 октября 2018

ΠŸΠΎΠΌΠ½ΠΈΡ‚ΡŒ всС: дСлимся Π»ΡƒΡ‡ΡˆΠ΅ΠΉ ΡˆΠΏΠ°Ρ€Π³Π°Π»ΠΊΠΎΠΉ ΠΏΠΎ Python

ΠœΡ‹ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΠ»ΠΈ ΠΎΡ‡Π΅Π½ΡŒ Π·Π°Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡŽ, которая ΠΏΠΎ ΠΏΡ€Π°Π²Ρƒ ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π°Π·Ρ‹Π²Π°...
Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
22 апрСля 2017

Английский язык для IT-спСциалистов

ВсСм людям, Ρ‚Π°ΠΊ ΠΈΠ»ΠΈ ΠΈΠ½Π°Ρ‡Π΅ связанным с IT сфСрой, прСкрасно извСстно, Ρ‡Ρ‚ΠΎ Ρ€Π°...
admin
29 января 2017

Π˜Π·ΡƒΡ‡Π°Π΅ΠΌ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡ‹: ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Π΅ ΠΊΠ½ΠΈΠ³ΠΈ, Π²Π΅Π±-сайты, ΠΎΠ½Π»Π°ΠΉΠ½-курсы ΠΈ Π²ΠΈΠ΄Π΅ΠΎΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹

Π’ этой ΠΏΠΎΠ΄Π±ΠΎΡ€ΠΊΠ΅ прСдставлСн список ΠΊΠ½ΠΈΠ³, Π²Π΅Π±-сайтов ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½-курсов, Π΄Π°ΡŽΡ‰ΠΈΡ…...