🎯 Ejemplos recomendados
Balanced sample collections from various categories for you to explore
Ejemplos de Manejo de Errores Web Go
Ejemplos de manejo de errores Web Go incluyendo captura de excepciones, registro y validación de parámetros
💻 Registro de Logs go
🟢 simple
⭐⭐⭐
Escribir logs en archivos con diferentes niveles y formatos
⏱️ 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 ===")
}
💻 Validación de Parámetros go
🟢 simple
⭐⭐⭐
Validar parámetros de función con validadores personalizados y mensajes de error
⏱️ 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 y Recover go
🟡 intermediate
⭐⭐⭐
Mecanismo de manejo de excepciones panic/recover en 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 ===")
}