🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Примеры Обработки Ошибок Web Go
Примеры обработки ошибок Web Go включая перехват исключений, логирование и валидацию параметров
💻 Логирование go
🟢 simple
⭐⭐⭐
Запись логов в файлы с различными уровнями и форматами
⏱️ 20 min
🏷️ go, web, error handling
Prerequisites:
Basic Go, log package, os package
// Web Go Logging Examples
// Logging to files with different levels and formats
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
)
// 1. Basic Logging
// BasicLogger wraps standard log package
type BasicLogger struct {
logger *log.Logger
}
func NewBasicLogger(output io.Writer) *BasicLogger {
return &BasicLogger{
logger: log.New(output, "", log.LstdFlags),
}
}
func (l *BasicLogger) Info(msg string) {
l.logger.Println("[INFO]", msg)
}
func (l *BasicLogger) Error(msg string) {
l.logger.Println("[ERROR]", msg)
}
func (l *BasicLogger) Warning(msg string) {
l.logger.Println("[WARNING]", msg)
}
func (l *BasicLogger) Debug(msg string) {
l.logger.Println("[DEBUG]", msg)
}
// 2. File Logging
// FileLogger writes logs to a file
type FileLogger struct {
file *os.File
logger *log.Logger
}
func NewFileLogger(filePath string) (*FileLogger, error) {
// Ensure directory exists
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("error creating directory: %v", err)
}
// Open/create log file
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, fmt.Errorf("error opening log file: %v", err)
}
return &FileLogger{
file: file,
logger: log.New(file, "", log.LstdFlags),
}, nil
}
func (l *FileLogger) Info(msg string) {
l.logger.Println("[INFO]", msg)
}
func (l *FileLogger) Error(msg string) {
l.logger.Println("[ERROR]", msg)
}
func (l *FileLogger) Warning(msg string) {
l.logger.Println("[WARNING]", msg)
}
func (l *FileLogger) Debug(msg string) {
l.logger.Println("[DEBUG]", msg)
}
func (l *FileLogger) Close() error {
return l.file.Close()
}
// 3. Level Logging
type LogLevel int
const (
DEBUG LogLevel = iota
INFO
WARNING
ERROR
)
// LevelLogger supports different log levels
type LevelLogger struct {
file *os.File
logger *log.Logger
minLevel LogLevel
levelNames map[LogLevel]string
}
func NewLevelLogger(filePath string, minLevel LogLevel) (*LevelLogger, error) {
// Ensure directory exists
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("error creating directory: %v", err)
}
// Open/create log file
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, fmt.Errorf("error opening log file: %v", err)
}
levelNames := map[LogLevel]string{
DEBUG: "DEBUG",
INFO: "INFO",
WARNING: "WARNING",
ERROR: "ERROR",
}
return &LevelLogger{
file: file,
logger: log.New(file, "", log.LstdFlags),
minLevel: minLevel,
levelNames: levelNames,
}, nil
}
func (l *LevelLogger) Log(level LogLevel, msg string) {
if level < l.minLevel {
return
}
l.logger.Println(fmt.Sprintf("[%s]", l.levelNames[level]), msg)
}
func (l *LevelLogger) Debug(msg string) {
l.Log(DEBUG, msg)
}
func (l *LevelLogger) Info(msg string) {
l.Log(INFO, msg)
}
func (l *LevelLogger) Warning(msg string) {
l.Log(WARNING, msg)
}
func (l *LevelLogger) Error(msg string) {
l.Log(ERROR, msg)
}
func (l *LevelLogger) Close() error {
return l.file.Close()
}
// 4. Structured Logging
// LogEntry represents a structured log entry
type LogEntry struct {
Timestamp time.Time
Level string
Message string
Fields map[string]interface{}
}
// StructuredLogger writes structured logs
type StructuredLogger struct {
file *os.File
encoder func(LogEntry) string
}
func NewStructuredLogger(filePath string) (*StructuredLogger, error) {
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, err
}
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, err
}
return &StructuredLogger{
file: file,
encoder: encodeJSON,
}, nil
}
func encodeJSON(entry LogEntry) string {
// Simple JSON encoding
fields := ""
for k, v := range entry.Fields {
fields += fmt.Sprintf(", %q: %v", k, v)
}
return fmt.Sprintf(
"{%q: %q, %q: %q, %q: %q%s}\n",
"timestamp", entry.Timestamp.Format(time.RFC3339),
"level", entry.Level,
"message", entry.Message,
fields,
)
}
func (l *StructuredLogger) Log(level, message string, fields map[string]interface{}) {
entry := LogEntry{
Timestamp: time.Now(),
Level: level,
Message: message,
Fields: fields,
}
l.file.WriteString(l.encoder(entry))
}
func (l *StructuredLogger) Close() error {
return l.file.Close()
}
// 5. Rotating File Logger
// RotatingLogger rotates log files when they reach a size limit
type RotatingLogger struct {
directory string
baseName string
maxSize int64
currentFile *os.File
currentSize int64
logger *log.Logger
}
func NewRotatingLogger(directory, baseName string, maxSizeMB int) (*RotatingLogger, error) {
if err := os.MkdirAll(directory, 0755); err != nil {
return nil, err
}
rl := &RotatingLogger{
directory: directory,
baseName: baseName,
maxSize: int64(maxSizeMB) * 1024 * 1024,
}
if err := rl.openNewFile(); err != nil {
return nil, err
}
return rl, nil
}
func (rl *RotatingLogger) openNewFile() error {
timestamp := time.Now().Format("20060102_150405")
filePath := filepath.Join(rl.directory, fmt.Sprintf("%s_%s.log", rl.baseName, timestamp))
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
rl.currentFile = file
rl.currentSize = 0
rl.logger = log.New(file, "", log.LstdFlags)
return nil
}
func (rl *RotatingLogger) checkRotation() error {
if rl.currentSize >= rl.maxSize {
rl.currentFile.Close()
return rl.openNewFile()
}
return nil
}
func (rl *RotatingLogger) Log(msg string) error {
if err := rl.checkRotation(); err != nil {
return err
}
rl.logger.Println(msg)
rl.currentSize += int64(len(msg)) + 1
return nil
}
func (rl *RotatingLogger) Close() error {
return rl.currentFile.Close()
}
// 6. Multiple Log Files
// MultiLogger writes to multiple log files
type MultiLogger struct {
loggers map[string]*log.Logger
files map[string]*os.File
}
func NewMultiLogger() *MultiLogger {
return &MultiLogger{
loggers: make(map[string]*log.Logger),
files: make(map[string]*os.File),
}
}
func (ml *MultiLogger) AddLogger(name, filePath string) error {
dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
ml.files[name] = file
ml.loggers[name] = log.New(file, "", log.LstdFlags)
return nil
}
func (ml *MultiLogger) Log(loggerName, msg string) {
if logger, ok := ml.loggers[loggerName]; ok {
logger.Println(msg)
}
}
func (ml *MultiLogger) Close() error {
var lastErr error
for _, file := range ml.files {
if err := file.Close(); err != nil {
lastErr = err
}
}
return lastErr
}
// 7. Context Logger
// ContextLogger adds context to log messages
type ContextLogger struct {
logger *log.Logger
context string
}
func NewContextLogger(output io.Writer, context string) *ContextLogger {
return &ContextLogger{
logger: log.New(output, "", log.LstdFlags),
context: context,
}
}
func (cl *ContextLogger) Log(msg string) {
cl.logger.Println(fmt.Sprintf("[%s] %s", cl.context, msg))
}
func (cl *ContextLogger) Info(msg string) {
cl.logger.Println(fmt.Sprintf("[INFO] [%s] %s", cl.context, msg))
}
// 8. Performance Logger
// PerformanceLogger logs execution time
type PerformanceLogger struct {
logger *log.Logger
start time.Time
}
func NewPerformanceLogger(output io.Writer) *PerformanceLogger {
return &PerformanceLogger{
logger: log.New(output, "", log.LstdFlags),
start: time.Now(),
}
}
func (pl *PerformanceLogger) LogOperation(operation string) {
elapsed := time.Since(pl.start)
pl.logger.Printf("[PERF] %s took %v", operation, elapsed)
pl.start = time.Now()
}
// Usage Examples
func main() {
fmt.Println("=== Web Go Logging Examples ===\n")
// 1. Basic logger
fmt.Println("--- 1. Basic Logger ---")
basic := NewBasicLogger(os.Stdout)
basic.Info("Application started")
basic.Error("An error occurred")
// 2. File logger
fmt.Println("\n--- 2. File Logger ---")
fileLogger, err := NewFileLogger("logs/app.log")
if err == nil {
fileLogger.Info("Logged to file")
fileLogger.Error("Error logged to file")
fileLogger.Close()
fmt.Println("Logs written to file")
}
// 3. Level logger
fmt.Println("\n--- 3. Level Logger ---")
levelLogger, _ := NewLevelLogger("logs/level.log", INFO)
levelLogger.Debug("This won't be logged")
levelLogger.Info("This will be logged")
levelLogger.Error("Errors are always logged")
levelLogger.Close()
// 4. Structured logger
fmt.Println("\n--- 4. Structured Logger ---")
structLogger, _ := NewStructuredLogger("logs/structured.log")
structLogger.Log("INFO", "User logged in", map[string]interface{}{
"user_id": 123,
"ip": "192.168.1.1",
})
structLogger.Close()
// 5. Rotating logger
fmt.Println("\n--- 5. Rotating Logger ---")
rotatingLogger, _ := NewRotatingLogger("logs", "app", 1) // 1MB
for i := 0; i < 100; i++ {
rotatingLogger.Log(fmt.Sprintf("Log entry %d", i))
}
rotatingLogger.Close()
// 6. Multi logger
fmt.Println("\n--- 6. Multi Logger ---")
multi := NewMultiLogger()
multi.AddLogger("app", "logs/app.log")
multi.AddLogger("error", "logs/error.log")
multi.Log("app", "Application log")
multi.Log("error", "Error log")
multi.Close()
// 7. Context logger
fmt.Println("\n--- 7. Context Logger ---")
ctx := NewContextLogger(os.Stdout, "AuthService")
ctx.Info("User authenticated")
// 8. Performance logger
fmt.Println("\n--- 8. Performance Logger ---")
perf := NewPerformanceLogger(os.Stdout)
time.Sleep(100 * time.Millisecond)
perf.LogOperation("Database query")
time.Sleep(50 * time.Millisecond)
perf.LogOperation("API call")
fmt.Println("\n=== All Logging Examples Completed ===")
}
💻 Валидация Параметров go
🟢 simple
⭐⭐⭐
Валидация параметров функции с пользовательскими валидаторами и сообщениями об ошибках
⏱️ 25 min
🏷️ go, web, error handling
Prerequisites:
Basic Go, reflect package
// Web Go Parameter Validation Examples
// Validate function parameters with custom validators
package main
import (
"errors"
"fmt"
"reflect"
"regexp"
"strings"
"unicode"
)
// 1. Basic Validation
// ValidateRequired checks if value is not empty
func ValidateRequired(value interface{}) error {
if value == nil {
return errors.New("value is required")
}
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.String:
if strings.TrimSpace(v.String()) == "" {
return errors.New("value cannot be empty")
}
case reflect.Slice, reflect.Map, reflect.Array:
if v.Len() == 0 {
return errors.New("value cannot be empty")
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if v.Int() == 0 {
return errors.New("value cannot be zero")
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if v.Uint() == 0 {
return errors.New("value cannot be zero")
}
case reflect.Float32, reflect.Float64:
if v.Float() == 0 {
return errors.New("value cannot be zero")
}
}
return nil
}
// ValidateMin checks if numeric value is >= min
func ValidateMin(value interface{}, min int) error {
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if v.Int() < int64(min) {
return fmt.Errorf("value must be at least %d", min)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if v.Uint() < uint64(min) {
return fmt.Errorf("value must be at least %d", min)
}
case reflect.Float32, reflect.Float64:
if v.Float() < float64(min) {
return fmt.Errorf("value must be at least %d", min)
}
default:
return errors.New("value must be numeric")
}
return nil
}
// ValidateMax checks if numeric value is <= max
func ValidateMax(value interface{}, max int) error {
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if v.Int() > int64(max) {
return fmt.Errorf("value must be at most %d", max)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if v.Uint() > uint64(max) {
return fmt.Errorf("value must be at most %d", max)
}
case reflect.Float32, reflect.Float64:
if v.Float() > float64(max) {
return fmt.Errorf("value must be at most %d", max)
}
default:
return errors.New("value must be numeric")
}
return nil
}
// ValidateLength checks string/slice length
func ValidateLength(value interface{}, min, max int) error {
v := reflect.ValueOf(value)
var length int
switch v.Kind() {
case reflect.String:
length = len(strings.TrimSpace(v.String()))
case reflect.Slice, reflect.Map, reflect.Array:
length = v.Len()
default:
return errors.New("value must be string, slice, or array")
}
if length < min {
return fmt.Errorf("length must be at least %d", min)
}
if max > 0 && length > max {
return fmt.Errorf("length must be at most %d", max)
}
return nil
}
// 2. String Validation
// ValidateEmail validates email format
func ValidateEmail(email string) error {
email = strings.TrimSpace(email)
if email == "" {
return errors.New("email is required")
}
// Basic email regex
emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$`)
if !emailRegex.MatchString(email) {
return errors.New("invalid email format")
}
return nil
}
// ValidateURL validates URL format
func ValidateURL(url string) error {
url = strings.TrimSpace(url)
if url == "" {
return errors.New("URL is required")
}
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
return errors.New("URL must start with http:// or https://")
}
return nil
}
// ValidatePhone validates phone number format
func ValidatePhone(phone string) error {
phone = strings.TrimSpace(phone)
if phone == "" {
return errors.New("phone number is required")
}
// Remove common separators
phone = strings.ReplaceAll(phone, " ", "")
phone = strings.ReplaceAll(phone, "-", "")
phone = strings.ReplaceAll(phone, "(", "")
phone = strings.ReplaceAll(phone, ")", "")
// Check if digits only
phoneRegex := regexp.MustCompile(`^\\d{10,15}$`)
if !phoneRegex.MatchString(phone) {
return errors.New("invalid phone number format")
}
return nil
}
// ValidatePassword validates password strength
func ValidatePassword(password string) error {
if len(password) < 8 {
return errors.New("password must be at least 8 characters")
}
var (
hasUpper bool
hasLower bool
hasNumber bool
hasSpecial bool
)
for _, char := range password {
switch {
case unicode.IsUpper(char):
hasUpper = true
case unicode.IsLower(char):
hasLower = true
case unicode.IsNumber(char):
hasNumber = true
case unicode.IsPunct(char) || unicode.IsSymbol(char):
hasSpecial = true
}
}
if !hasUpper {
return errors.New("password must contain uppercase letter")
}
if !hasLower {
return errors.New("password must contain lowercase letter")
}
if !hasNumber {
return errors.New("password must contain number")
}
if !hasSpecial {
return errors.New("password must contain special character")
}
return nil
}
// 3. Numeric Validation
// ValidateRange checks if value is in range [min, max]
func ValidateRange(value, min, max int) error {
if value < min || value > max {
return fmt.Errorf("value must be between %d and %d", min, max)
}
return nil
}
// ValidatePositive checks if value is positive
func ValidatePositive(value int) error {
if value <= 0 {
return errors.New("value must be positive")
}
return nil
}
// ValidateNegative checks if value is negative
func ValidateNegative(value int) error {
if value >= 0 {
return errors.New("value must be negative")
}
return nil
}
// ValidatePositiveFloat checks if float value is positive
func ValidatePositiveFloat(value float64) error {
if value <= 0 {
return errors.New("value must be positive")
}
return nil
}
// 4. Date/Time Validation
// ValidateAge validates age range
func ValidateAge(age int) error {
return ValidateRange(age, 0, 150)
}
// ValidateYear validates year
func ValidateYear(year int) error {
const minYear = 1900
const maxYear = 2100
return ValidateRange(year, minYear, maxYear)
}
// 5. Custom Validators
// Validator function type
type Validator func(interface{}) error
// ValidateWith runs custom validator
func ValidateWith(value interface{}, validator Validator) error {
return validator(value)
}
// ValidateStruct validates struct fields
func ValidateStruct(obj interface{}) error {
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return errors.New("expected struct")
}
t := v.Type()
var errs []string
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
fieldValue := v.Field(i)
// Check for "validate" tag
tag := field.Tag.Get("validate")
if tag != "" {
// Parse validation rules
rules := strings.Split(tag, ",")
for _, rule := range rules {
if err := applyValidationRule(fieldValue, rule); err != nil {
errs = append(errs, fmt.Sprintf("%s: %v", field.Name, err))
}
}
}
}
if len(errs) > 0 {
return fmt.Errorf("validation errors: %s", strings.Join(errs, "; "))
}
return nil
}
func applyValidationRule(value reflect.Value, rule string) error {
parts := strings.Split(rule, "=")
name := parts[0]
switch name {
case "required":
return ValidateRequired(value.Interface())
case "min":
if len(parts) == 2 {
min := parseInt(parts[1])
return ValidateMin(value.Interface(), min)
}
case "max":
if len(parts) == 2 {
max := parseInt(parts[1])
return ValidateMax(value.Interface(), max)
}
}
return nil
}
func parseInt(s string) int {
var i int
fmt.Sscanf(s, "%d", &i)
return i
}
// 6. Validation Result
// ValidationResult holds validation results
type ValidationResult struct {
Valid bool
Errors map[string]string
}
// NewValidationResult creates new validation result
func NewValidationResult() *ValidationResult {
return &ValidationResult{
Valid: true,
Errors: make(map[string]string),
}
}
// AddError adds error to validation result
func (vr *ValidationResult) AddError(field, message string) {
vr.Valid = false
vr.Errors[field] = message
}
// IsValid returns true if no errors
func (vr *ValidationResult) IsValid() bool {
return vr.Valid
}
// GetErrors returns all errors
func (vr *ValidationResult) GetErrors() map[string]string {
return vr.Errors
}
// Error returns error message
func (vr *ValidationResult) Error() string {
if vr.Valid {
return ""
}
var errs []string
for field, msg := range vr.Errors {
errs = append(errs, fmt.Sprintf("%s: %s", field, msg))
}
return strings.Join(errs, "; ")
}
// 7. Validation Builder
// ValidationBuilder builds validation rules
type ValidationBuilder struct {
result *ValidationResult
value interface{}
}
func NewValidationBuilder(value interface{}) *ValidationBuilder {
return &ValidationBuilder{
result: NewValidationResult(),
value: value,
}
}
func (vb *ValidationBuilder) Required() *ValidationBuilder {
if err := ValidateRequired(vb.value); err != nil {
vb.result.AddError("required", err.Error())
}
return vb
}
func (vb *ValidationBuilder) Min(min int) *ValidationBuilder {
if err := ValidateMin(vb.value, min); err != nil {
vb.result.AddError("min", err.Error())
}
return vb
}
func (vb *ValidationBuilder) Max(max int) *ValidationBuilder {
if err := ValidateMax(vb.value, max); err != nil {
vb.result.AddError("max", err.Error())
}
return vb
}
func (vb *ValidationBuilder) Validate() *ValidationResult {
return vb.result
}
// 8. Example Usage
type User struct {
Name string `validate:"required"`
Age int `validate:"required,min=18,max=120"`
Email string
Password string
}
func ValidateUser(user User) *ValidationResult {
result := NewValidationResult()
// Validate name
if user.Name == "" {
result.AddError("name", "name is required")
}
if len(user.Name) < 2 {
result.AddError("name", "name must be at least 2 characters")
}
// Validate age
if user.Age < 18 {
result.AddError("age", "must be at least 18")
}
if user.Age > 120 {
result.AddError("age", "must be at most 120")
}
// Validate email
if err := ValidateEmail(user.Email); err != nil {
result.AddError("email", err.Error())
}
// Validate password
if err := ValidatePassword(user.Password); err != nil {
result.AddError("password", err.Error())
}
return result
}
// Usage Examples
func main() {
fmt.Println("=== Web Go Parameter Validation Examples ===\n")
// 1. Required validation
fmt.Println("--- 1. Required Validation ---")
err := ValidateRequired("")
if err != nil {
fmt.Printf("Error: %v\n", err)
}
err = ValidateRequired("value")
fmt.Printf("Valid: %v\n", err == nil)
// 2. Range validation
fmt.Println("\n--- 2. Range Validation ---")
err = ValidateMin(5, 10)
fmt.Printf("Min error: %v\n", err)
err = ValidateRange(15, 10, 20)
fmt.Printf("Range valid: %v\n", err == nil)
// 3. String validation
fmt.Println("\n--- 3. String Validation ---")
err = ValidateEmail("invalid-email")
fmt.Printf("Email error: %v\n", err)
err = ValidateEmail("[email protected]")
fmt.Printf("Email valid: %v\n", err == nil)
// 4. Password validation
fmt.Println("\n--- 4. Password Validation ---")
err = ValidatePassword("weak")
fmt.Printf("Password error: %v\n", err)
err = ValidatePassword("StrongPass123!")
fmt.Printf("Password valid: %v\n", err == nil)
// 5. User validation
fmt.Println("\n--- 5. User Validation ---")
user := User{
Name: "John",
Age: 25,
Email: "[email protected]",
Password: "Password123!",
}
result := ValidateUser(user)
if result.IsValid() {
fmt.Println("User is valid")
} else {
fmt.Printf("User validation errors: %v\n", result.Error())
}
// 6. Validation builder
fmt.Println("\n--- 6. Validation Builder ---")
builderResult := NewValidationBuilder(15).
Required().
Min(10).
Max(20).
Validate()
if builderResult.IsValid() {
fmt.Println("Builder validation passed")
} else {
fmt.Printf("Builder errors: %v\n", builderResult.Error())
}
fmt.Println("\n=== All Parameter Validation Examples Completed ===")
}
💻 Panic и Recover go
🟡 intermediate
⭐⭐⭐
Механизм обработки исключений panic/recover в Go
⏱️ 25 min
🏷️ go, web, error handling
Prerequisites:
Intermediate Go, runtime package
// Web Go Panic/Recover Examples
// Exception handling with panic and recover in Go
package main
import (
"errors"
"fmt"
"runtime"
"strings"
)
// 1. Basic Panic and Recover
// BasicPanicExample demonstrates basic panic
func BasicPanicExample() {
fmt.Println("Before panic")
panic("Something went wrong!")
fmt.Println("This will not be printed") // This line is unreachable
}
// RecoverExample demonstrates recover catching panic
func RecoverExample() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic: %v", r)
fmt.Printf("Recovered: %v\n", r)
}
}()
fmt.Println("Before panic")
panic("Something went wrong!")
fmt.Println("This will not be printed")
return nil
}
// 2. Panic with Values
// PanicWithString panics with string message
func PanicWithString() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovered string: %v\n", r)
}
}()
panic("error occurred")
}
// PanicWithError panics with error
func PanicWithError() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
fmt.Printf("Recovered error: %v\n", err)
}
}
}()
panic(errors.New("something went wrong"))
}
// PanicWithCustomType panics with custom type
type CustomError struct {
Code int
Message string
}
func (e CustomError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func PanicWithCustomType() {
defer func() {
if r := recover(); r != nil {
if customErr, ok := r.(CustomError); ok {
fmt.Printf("Recovered custom error: %v\n", customErr)
}
}
}()
panic(CustomError{Code: 404, Message: "Not found"})
}
// 3. Panic in Functions
// Divide divides two numbers, panics on division by zero
func Divide(a, b int) int {
if b == 0 {
panic("division by zero")
}
return a / b
}
// SafeDivide safely divides with panic recovery
func SafeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic recovered: %v", r)
}
}()
result = Divide(a, b)
return result, nil
}
// 4. Panic in Goroutines
// GoroutineWithPanic demonstrates panic in goroutine
func GoroutineWithPanic() {
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Goroutine recovered: %v\n", r)
}
}()
fmt.Println("Goroutine starting")
panic("goroutine panic")
}()
}
// 5. Panic with Stack Trace
// PanicWithStackTrace prints stack trace on panic
func PanicWithStackTrace() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovered: %v\n", r)
fmt.Println("Stack trace:")
// Get stack trace
buf := make([]byte, 4096)
n := runtime.Stack(buf, false)
fmt.Println(string(buf[:n]))
}
}()
panic("error with stack trace")
}
// GetStackTrace gets current stack trace
func GetStackTrace(skip int) string {
buf := make([]byte, 4096)
n := runtime.Stack(buf, false)
return string(buf[:skip*10 : n]) // Skip some frames
}
// 6. Named Return Values with Recover
// ProcessWithRecover uses named return value with recover
func ProcessWithRecover() (result string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic in ProcessWithRecover: %v", r)
}
}()
// Some processing that might panic
if somethingBadHappens() {
panic("processing failed")
}
result = "success"
return result, nil
}
func somethingBadHappens() bool {
return true
}
// 7. Panic Wrapping
// WrapPanic wraps panic with additional context
func WrapPanic() {
defer func() {
if r := recover(); r != nil {
// Wrap with additional context
panic(fmt.Errorf("wrapped panic: %w", fmt.Errorf("%v", r)))
}
}()
panic("original panic")
}
// SafeWrapPanic safely wraps panic
func SafeWrapPanic() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("wrapped: %v", r)
}
}()
panic("original panic")
return nil
}
// 8. Conditional Panic
// PanicIf panics if condition is true
func PanicIf(condition bool, message string) {
if condition {
panic(message)
}
}
// PanicUnless panics unless condition is true
func PanicUnless(condition bool, message string) {
if !condition {
panic(message)
}
}
// PanicOnError panics if error is not nil
func PanicOnError(err error, message string) {
if err != nil {
panic(fmt.Sprintf("%s: %v", message, err))
}
}
// 9. Panic Handlers
// ErrorHandler handles panics in a reusable way
func ErrorHandler(fn func()) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic caught: %v", r)
}
}()
fn()
return nil
}
// ExecuteSafely executes function safely with panic recovery
func ExecuteSafely(fn func() error) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic recovered: %v", r)
}
}()
return fn()
}
// 10. Panic with Cleanup
// ProcessWithCleanup processes with cleanup on panic
func ProcessWithCleanup() (err error) {
// Setup resource
resource := acquireResource()
defer func() {
// Cleanup happens even on panic
resource.Release()
if r := recover(); r != nil {
err = fmt.Errorf("panic during processing: %v", r)
}
}()
// Use resource (might panic)
resource.Use()
return nil
}
type Resource struct {
name string
}
func acquireResource() *Resource {
return &Resource{name: "resource"}
}
func (r *Resource) Use() {
fmt.Printf("Using %s\n", r.name)
// Simulate panic
panic("resource use failed")
}
func (r *Resource) Release() {
fmt.Printf("Releasing %s\n", r.name)
}
// 11. Panic Recovery Middleware
// RecoveryMiddleware wraps function with recovery
func RecoveryMiddleware(fn func()) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Middleware recovered: %v\n", r)
}
}()
fn()
}
// Usage Examples
func main() {
fmt.Println("=== Web Go Panic/Recover Examples ===\n")
// 1. Basic panic (would crash without recovery)
fmt.Println("--- 1. Panic with Recover ---")
err := RecoverExample()
if err != nil {
fmt.Printf("Caught error: %v\n", err)
}
// 2. Panic with different values
fmt.Println("\n--- 2. Panic with Different Values ---")
PanicWithString()
PanicWithError()
PanicWithCustomType()
// 3. Safe division
fmt.Println("\n--- 3. Safe Division ---")
result, err := SafeDivide(10, 2)
if err == nil {
fmt.Printf("10 / 2 = %d\n", result)
}
result, err = SafeDivide(10, 0)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
// 4. Stack trace
fmt.Println("\n--- 4. Stack Trace ---")
PanicWithStackTrace()
// 5. Error handler
fmt.Println("\n--- 5. Error Handler ---")
err = ErrorHandler(func() {
panic("handled panic")
})
if err != nil {
fmt.Printf("Handler caught: %v\n", err)
}
// 6. Execute safely
fmt.Println("\n--- 6. Execute Safely ---")
err = ExecuteSafely(func() error {
panic("safe execution")
})
if err != nil {
fmt.Printf("Safe execution error: %v\n", err)
}
// 7. Conditional panic
fmt.Println("\n--- 7. Conditional Panic ---")
PanicIf(false, "This won't panic")
fmt.Println("No panic occurred")
// 8. Middleware
fmt.Println("\n--- 8. Recovery Middleware ---")
RecoveryMiddleware(func() {
panic("middleware panic")
})
// 9. Cleanup on panic
fmt.Println("\n--- 9. Cleanup on Panic ---")
ProcessWithCleanup()
fmt.Println("\n=== All Panic/Recover Examples Completed ===")
}