{"id":23387092,"url":"https://github.com/thehamdiz/it","last_synced_at":"2025-05-16T09:02:41.700Z","repository":{"id":262112299,"uuid":"886243352","full_name":"theHamdiz/it","owner":"theHamdiz","description":"A collection of helpful error handling, performance measuring, execution retrial, benchmarking \u0026 other useful patterns for golang under one package.","archived":false,"fork":false,"pushed_at":"2025-02-05T20:45:04.000Z","size":214,"stargazers_count":427,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-09T03:14:15.914Z","etag":null,"topics":["colors","go","golang","logging","measuring","retriable","timing"],"latest_commit_sha":null,"homepage":"https://hamdiz.me","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/theHamdiz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-10T15:15:43.000Z","updated_at":"2025-03-28T06:22:07.000Z","dependencies_parsed_at":"2024-11-10T16:35:03.984Z","dependency_job_id":"607da966-4b10-43c2-bcfb-2dd5a8ceed73","html_url":"https://github.com/theHamdiz/it","commit_stats":null,"previous_names":["thehamdiz/it"],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theHamdiz%2Fit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theHamdiz%2Fit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theHamdiz%2Fit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theHamdiz%2Fit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theHamdiz","download_url":"https://codeload.github.com/theHamdiz/it/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501548,"owners_count":22081526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["colors","go","golang","logging","measuring","retriable","timing"],"created_at":"2024-12-22T01:14:35.210Z","updated_at":"2025-05-16T09:02:41.661Z","avatar_url":"https://github.com/theHamdiz.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# it 🎭\n\nBecause we kinda need this shit daily and we know it!\n\n[![GoDoc](https://godoc.org/github.com/theHamdiz/it?status.svg)](https://pkg.go.dev/github.com/theHamdiz/it)\n[![Go Report Card](https://goreportcard.com/badge/github.com/theHamdiz/it)](https://goreportcard.com/report/github.com/theHamdiz/it)\n[![License: The Whatever, Just Take It License](https://img.shields.io/badge/License-MIT-yellow.svg)](TRUELICENSE)\n![Tests](https://img.shields.io/badge/tests-mostly%20passing-green)\n![Panic Rate](https://img.shields.io/badge/panic%20rate-just%20right-blue)\n\n## Installation 🚀\n\n```bash\ngo get github.com/theHamdiz/it\n```\n\n## Core Features\n\n### Error Handling (Because panic() is a lifestyle)\n\n```go\nimport \"github.com/theHamdiz/it\"\n\n// The \"I believe in miracles\" approach\nconfig := it.Must(LoadConfig())\n\n// The \"let's log and pray\" method\nuser := it.Should(GetUser())\n\n// Maybe we'll connect to the database... eventually\nmaybeConnect := it.Could(func() (*sql.DB, error) {\n    return sql.Open(\"postgres\", \"postgres://procrastinator:later@localhost\")\n})\n\n// Sometime later, when we feel ready...\ndb := maybeConnect() // First call actually does the work\nalsoDb := maybeConnect() // Returns same result, wasn't worth trying again anyway\n\nif value, ok := it.Might(maybeThisWorks); ok {\n    // Nice, we got something\n} else {\n    // No biggie, we weren't counting on it anyway\n}\n\n// The \"cover your tracks\" strategy\nerr := it.WrapError(dbErr, \"database had an existential crisis\",\n    map[string]any{\"attempt\": 42, \"mood\": \"gothic\"})\n```\n\n### SafeGo - Panic-Proof Goroutines\n\nBecause letting goroutines die alone in the dark is just cruel.\n\n```go\nimport \"github.com/theHamdiz/it\"\n\n// Fire and forget (but not really)\nit.SafeGo(func() {\n    DoSomethingDangerous()  // We'll catch you if you fall\n})\n\n// For the context-aware crowd\nit.SafeGoWithContext(ctx, func(ctx context.Context) {\n    ResponsiblyDangerous(ctx)  // Safety first, but make it contextual\n})\n```\n\nIncludes automatic panic recovery and proper context propagation. Perfect for when you want to live dangerously but with a safety net.\n\nNow go forth and spawn goroutines without fear of them taking your program down with them.\n\n\n### Logging (Now with proper prefixes)\n\n```go\nimport \"github.com/theHamdiz/it\"\n\nit.Trace(\"Like println() but fancier\")\nit.Debug(\"For when you're feeling verbose\")\nit.Info(\"FYI: Something happened\")\nit.Warn(\"Houston, we have a potential problem\")\nit.Error(\"Everything is fine 🔥\")\nit.Audit(\"For when legal is watching\")\n\n// Structured logging (because JSON makes everything enterpriseTM)\nit.StructuredInfo(\"API Call\", map[string]any{\n    \"status\": 200,\n    \"response_time\": \"too long\",\n    \"excuse\": \"network congestion\"\n})\n```\n\n## Sub-Packages (For the Control Freaks)\n\n### Pool - Object Recycling Center\n\n```go\nimport \"github.com/theHamdiz/it/pool\"\n\npool_ := pool.NewPool(func() *ExpensiveObject {\n    // Save the environment, reuse your objects\n    return \u0026ExpensiveObject{}\n})\nobj := pool_.Get()\n// Return your shopping cart\ndefer pool_.Put(obj)\n```\n\n### Debouncer - Function Anger Management\n\n```go\nimport \"github.com/theHamdiz/it/debouncer\"\n\ncalm := debouncer.NewDebouncer(100 * time.Millisecond)\nrelaxedFunc := calm.Debounce(func() {\n    // Now with less spam\n    NotifyEveryone(\"Updates!\")\n})\n```\n\n### Load Balancer - Work Distribution Committee\n\n```go\nimport \"github.com/theHamdiz/it/lb\"\n\n// Democratic work distribution\nlb_ := lb.NewLoadBalancer(10)\nerr := lb_.Execute(ctx, func() error {\n    // Share the pain\n    return HeavyLifting()\n})\n```\n\n### Benchmarker - The Performance Theater\n\nBecause measuring performance makes you feel better about your terrible code.\n\n```go\nimport \"github.com/theHamdiz/it/bm\"\n\n// Run your function until the numbers look good\nresult := bm.Benchmark(\"definitely-fast\", 1000, func() {\n    SuperOptimizedCode() // yeah right\n})\n\n// Or collect your own timings when you don't trust us\ntimings := []time.Duration{...}\nresult := bm.AnalyzeBenchmark(\"probably-fast\", timings)\n\n// Slack-friendly output for bragging rights\nfmt.Println(result) // Screenshots or it didn't happen\n```\n\nGives you min, max, average, median, and that standard deviation thing nobody really understands. Perfect for making your code look faster than it is in production.\n\nJSON support included because apparently everything needs to be in a dashboard these days.\n\nNow go forth and benchmark the hell out of that O(n2) algorithm you're trying to justify.\n\n### Exponential Backoff - Professional Failure Management\n\nBecause at some point, everything fails. Might as well be ready for it.\n\n```go\nimport \"github.com/theHamdiz/it/retry\"\n\n// For when you're feeling optimistic\ncfg := retry.DefaultRetryConfig()\n\n// For when you know it's going to be rough\ncfg := retry.Config{\n    Attempts:     5,\n    InitialDelay: time.Second,\n    MaxDelay:     30 * time.Second,\n    Multiplier:   2.0,\n    RandomFactor: 0.1,\n}\n\n// Actually doing the thing\nresult, err := retry.WithBackoff(ctx, cfg, func(ctx context.Context) (string, error) {\n    return CallThatFlakyService()\n})\n```\n\nImplements exponential backoff with jitter because hammering a failing service is both rude and stupid. Comes with sane defaults for when you're too lazy to think.\n\nDefault config gives you 3 attempts with increasing delays, starting at 100ms and capping at 10s. Add some randomness to avoid the thundering herd, because your systems have enough problems already.\n\nNow go forth and embrace failure like a professional.\n\n### Shutdown Manager - Graceful Program Retirement\n\nBecause even software needs a dignified exit strategy.\n\n```go\nimport \"github.com/theHamdiz/it/sm\"\n\n// Set up the end times\nsm_ := sm.NewShutdownManager()\n\n// Add some last wishes\nsm_.AddAction(\n    \"save-data\",\n    func(ctx context.Context) error {\n        return db.Close()\n    },\n    5 * time.Second,\n    true, // This one matters\n)\n\n// Start watching for the end\nsm_.Start()\n\n// Wait for the inevitable\nif err := sm_.Wait(); err != nil {\n    log.Fatal(\"Failed to die gracefully:\", err)\n}\n```\n\n```go\n// Or just use the global shortcut (for the pragmatists)\nimport \"github.com/theHamdiz/it\"\n\nit.GracefulShutdown(ctx, server, 30*time.Second, done, func() {\n    // Your last words here\n})\n\n// Need a phoenix-like rebirth?\nit.GracefulRestart(ctx, server, 30*time.Second, done, func() {\n    // Rise from the ashes\n})\n```\n\nHandles shutdown signals (SIGINT, SIGTERM by default), manages cleanup tasks with timeouts, and ensures your program dies with dignity instead of just crashing.\n\nCritical actions fail the whole shutdown if they fail, non-critical ones just log and continue, because some things aren't worth dying twice over.\n\nPerfect for when you need your program to clean up after itself instead of leaving a mess for the OS to deal with.\n\n### Rate Limiter - Traffic Control for Functions\n\n```go\n// The proper way (for when you need full control)\nimport \"github.com/theHamdiz/it/rl\"\n\nlimiter := rl.NewRateLimiter(time.Second, 10)\ndefer limiter.Close()\n\nerr := limiter.Execute(ctx, func() error {\n    return DoSomethingFast()  // But not too fast\n})\n\n// Or better yet, with actual returns\nresult, err := rl.ExecuteRateLimited(limiter, ctx, func() (string, error) {\n    return GetSomethingQuickly()  // Responsibly quick\n})\n```\n\n```go\n// The shortcut (for the rest of us)\nimport \"github.com/theHamdiz/it\"\n\n// Turn any function into a well-behaved citizen\nchillVersion := it.RateLimiter(time.Second, func() string {\n    return IWouldSpamThisIfICould()\n}).(func() string)\n\n// Usage:\nresult := chillVersion()  // Now properly paced\n\n// Waiting (but not forever)\nsuccess := it.WaitFor(5*time.Second, func() bool {\n    return systemIsReady()  // Are we there yet?\n})\n\nif !success {\n    // Time to give up and go home\n}\n```\n\nPerfect for when your functions need to learn some self-control, without all the ceremony.\n\nNow go forth and rate limit responsibly. Your servers will thank you.\n\n### Time Keeper - Time Tracking for the Obsessed\n\nBecause if you're not measuring it, you're just guessing.\n\n```go\nimport \"github.com/theHamdiz/it/tk\"\n\n// Basic timing\ntk_ := tk.NewTimeKeeper(\"database-query\").Start()\ndefer tk_.Stop()\n\n// With a callback for the micromanagers\ntk_ := tk.NewTimeKeeper(\"expensive-operation\",\n    tk.WithCallback(func(d time.Duration) {\n        metrics.Record(\"too-slow\", d)\n    }),\n).Start()\n\n// Quick one-liner for the lazy\nresult := tk.TimeFn(\"important-stuff\", func() string {\n    return DoTheWork()\n})\n\n// Async timing for the parallel obsessed\natk := tk.NewAsyncTimeKeeper(\"batch-process\")\nfor task := range tasks {\n    atk.Track(func() { process(task) })\n}\ndurations := atk.Wait()\n```\n\n```go\n// The dirty shortcut approach!!\nimport \"github.com/theHamdiz/it\"\n\nresult := it.TimeFunction(\"critical-operation\", func() string {\n    return DoSomethingWorthTiming()\n})\n\n// Block timing with defer\ndefer it.TimeBlock(\"expensive-stuff\")()\n\n// Custom timing callback\nit.TimeFunctionWithCallback(\"important-task\",\n    func() string {\n        return ExpensiveOperation()\n    },\n    func(d time.Duration) {\n        if d \u003e time.Second {\n            alertSomeone()  // Someone's being slow\n    },\n)\n\n// Parallel timing (for the impatient)\ndurations := it.TimeParallel(\"batch-process\",\n    func() { task1() },\n    func() { task2() },\n    func() { task3() },\n)\n// Now you know which one to blame\n```\n\nTimes your operations, logs the results, and lets you obsess over performance with minimal effort. Supports both synchronous and async operations, because sometimes you need to time multiple failures simultaneously.\n\nPerfect for when you need to prove that it's not your code that's slow, it's everyone else's.\n\n### Circuit Breaker - Your Code's Emotional Support System\n\nBecause sometimes your dependencies need a time-out, just like your ex.\n\n```go\nimport \"github.com/theHamdiz/it/cb\"\n\n// Create a breaker that gives up after 3 failures\n// and needs 30 seconds of alone time\nbreaker := cb.NewCircuitBreaker(3, 30*time.Second)\n\n// Wrap your flaky calls with trust issues\nerr := breaker.Execute(func() error {\n    return ThatThingThatAlwaysBreaks()\n})\n\n// Check if we're still in therapy\nif breaker.IsOpen() {\n    // Time to implement plan B\n}\n```\n\nIncludes state tracking, configurable thresholds, and automatic recovery. Perfect for when your microservices are having a midlife crisis.\n\nNow go forth and fail gracefully, because that's what mature code does.\n\n### Result - Because nil Checks Are So 1970s\n\n```go\nimport \"github.com/theHamdiz/it/result\"\n\n// For the optimists\nres := result.Ok(\"success\")\nif res.IsOk() {\n    value := res.UnwrapOr(\"plan B\")\n}\n\n// For the realists\nres := result.Try(func() string {\n    return maybeExplode()\n}).OrElse(func() Result[string] {\n    return Ok(\"at least we tried\")\n})\n\n// For the functional programming enthusiasts\nresult.Ok(42).\n    Filter(isNotTooLarge).\n    Map(addOne).\n    Match(\n        func(n int) { fmt.Println(\"Yay:\", n) },\n        func(err error) { /* pretend this never happened */ },\n    )\n\n// For those who like to live dangerously\nvalue := result.Some(42).UnwrapOrPanic() // YOLO\n\n// For the overachievers\npairs := result.Zip(\n    result.Ok(\"hello\"),\n    result.Ok(42),\n) // Because one value isn't complicated enough\n\n// For when you need to fail collectively\nresults := result.Collect([]Result[int]{\n    Ok(1), Ok(2), Err[int](errors.New(\"oops\"))\n}) // Misery loves company\n```\n\nBecause if you're going to handle errors, you might as well do it with style.\nNow with 100% more Option types, because nil was getting lonely.\n\n### Math - For The Algorithmically Gifted\n\n```go\nimport \"github.com/theHamdiz/it/math\"\n\n// O(1) summation that would make Gauss proud\nsum := math.Sum(1000000)\n\n// Want to sum a specific range? We've got you covered\nrangeSum := math.SumRange(42, 100)\n\n// Need overflow protection? We're responsible adults here\nsafeSum, err := math.SumWithOverflowCheck(1000000)\n\n// Living dangerously? MustSum will panic if things go wrong\nyoloSum := math.MustSum(1000000)\n\n// Sum of squares in O(1) because why not?\nsquares := math.SumOfSquares(100)\n\n// Sum of cubes, because squares are so last century\ncubes := math.SumOfCubes(50)\n\n// Fourth powers, for when you really want to show off\nfourthPowers := math.SumOfFourthPowers(25)\n\n// Arithmetic series for the classically inclined\narithmetic := math.ArithmeticSeries(1, 2, 100) // 1, 3, 5, ...\n\n// Geometric series for the exponentially minded\ngeometric := math.GeometricSeries(1, 2, 10) // 1, 2, 4, 8, ...\n\n// Fast exponentiation because we're not savages\npower := math.Pow(2, 10)\n\n// Factorial without the stack overflow drama\nfactorial, err := math.Factorial(10)\n\n// Need an approximation? Stirling's got your back\napproxFact := math.FactorialStirlingApprox(100)\n\n// Binomial coefficients without the tears\nchoose, err := math.Binomial(20, 10)\n\n// Fibonacci that won't make your CPU cry\nfib := math.Fibonacci(42)\n```\n\nUltimate Security Suite – When “Good Enough” Isn’t Good Enough\n\n```go\nimport \"github.com/theHamdiz/it\"\n\n// When you need a secret that's totally random*:\nsecret := it.GenerateSecret(32)\n// *Usually uses crypto/rand, but if that fails... well, we get creative with time.\n// It's like using your birthday as a password, but with nanoseconds. Security through obscurity!\n\n// When your password is too lazy to protect itself:\nhashed, err := it.HashPassword(\"mySuperSecret\", 12)\n// Your password is sent to a rigorous bootcamp (bcrypt rounds), emerging as a hardened hash with its own unique salt.\n// If the bootcamp fails, you'll get a polite error message.\n\n// Think your password can waltz past the velvet rope?\nerr = it.VerifyPassword(hashed, \"mySuperSecret\")\n// If err is nil, congratulations—your password made the cut.\n// Otherwise, it's like a bouncer telling you, \"Not on the list, buddy.\"\n```\n\nNow go forth and generate cryptographically convincing secrets, hash those passwords like they’re training for a marathon, and verify them with the confidence of a seasoned doorman. Enjoy your Ultimate Security Suite—because sometimes, even security needs a little swagger.\n\n### Config - Because Hardcoding is a Crime\n\nFor when you need to make your application configurable, but still predictably unreliable.\n\n```go\nimport (\n\t\"github.com/theHamdiz/it/logger\"\n\t\"github.com/theHamdiz/it/cfg\"\n)\n\n// You could use global shortcuts\n// Redirect logs to your favorite black hole\nfile, _ := os.OpenFile(\"void.log\", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)\nit.SetLogOutput(file)\n\n// Set log level from \"meh\" to \"everything's on fire\"\nit.SetLogLevel(logger.LevelDebug)\n\n// Let environment variables do the heavy lifting\n// Optimist mode\nos.Setenv(\"LOG_LEVEL\", \"PANIC\")\n// The ultimate backup strategy\nos.Setenv(\"LOG_FILE\", \"/dev/null\")\nit.InitFromEnv()\n\n// Or you could create a config with sensible* defaults\n// *sensible is a relative term\ncfg_ := cfg.Configure(\n    cfg.WithLogLevel(logger.LevelDebug),    // Maximum verbosity\n    cfg.WithLogFile(\"regrets.log\"),         // For posterity\n    cfg.WithShutdownTimeout(5*time.Second), // Ain't nobody got time for that\n    cfg.WithColors(true),                   // Pretty errors are still errors\n)\n\n// Check what you did to yourself\nif cfg_.ColorsEnabled() {\n    // Congratulations, your logs are now fabulous\n}\n```\n\nIncludes functional options, reasonable defaults, and just enough flexibility to be dangerous. Perfect for when you need to explain why production is different from your laptop.\n\nNow go forth and configure responsibly, or don't. We're not your parents.\n\n\n### Version - Software Identity Management\n\nBecause every program needs to know who it is and who to blame.\n\n```go\n// Get all the details\ninfo := version.Get()\nfmt.Println(info)\n// Output: v1.2.3 built at 2023-12-25T12:00:00Z from main@abc1234 (go1.21) running on linux/amd64 in production\n\n// For your JSON APIs\njsonData, _ := json.Marshal(info.ToMap())\n\n// Build with:\ngo build -ldflags=\"\n    -X 'package/version.version=1.2.3'\n    -X 'package/version.buildTime=$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")'\n    -X 'package/version.gitCommit=$(git rev-parse HEAD)'\n    -X 'package/version.gitBranch=$(git rev-parse --abbrev-ref HEAD)'\n    -X 'package/version.environment=production'\"\n```\n\nTracks version, build time, git info, and runtime details. Perfect for logging, debugging, and finding out which commit broke production.\n\nValues are injected at build time via ldflags, because hardcoding versions is for amateurs.\n\n## Performance Notes\n\n- Everything is O(1)*\n- Memory usage is optimal**\n- CPU friendly***\n\n\\* Except when it isn't.\n\n\\**Compared to loading the entire Wikipedia into RAM.\n\n\\*** Your definition of friendly may vary LOL!\n\n\n## Known Features 🐛\n\n- Sometimes panics exactly when you expect\n- Occasionally logs the right thing\n- Works perfectly in production*\n\n\\* Results may vary\n\n## FAQ 🤔\n\n**Q: Is this production ready?**\nA: Define \"production\" and \"ready\"\n\n**Q: Why should I use this?**\nA: Because writing your own boilerplate is so 2020\n\n**Q: Is it fast?**\nA: Faster than your last deployment rollback\n\n## Contributing 🤝\n\n1. Fork (the repo, not your codebase)\n2. Create (bugs)\n3. Submit PR (with tests maybe?)\n4. Wait (like your HTTP requests)\n\n## License\n\n[The Whatever, Just Take It License](TRUELICENSE) - Because even chaos needs a license.\n\n\u003e P.S. Don't believe the `MIT LICENSE` File, it's just here for `go.dev`\n\n---\n\n## Actual Serious Note\n\nThis package provides robust utilities for:\n- Error handling and recovery.\n- Structured and leveled logging.\n- Some benchmarking functionalities.\n- Rate limiting, load balancing \u0026 a debouncer.\n- Some time keeping \u0026 measuring functionality.\n- Object pooling and resource management.\n- Mathematical optimizations - Some O(1) goodies.\n- Graceful shutdowns \u0026 restarts.\n- Some version management/reporting stuff.\n- Oh yeah \u0026 a circuit breaker, whatever that might be.\n\nDocumentation: [GoDoc](https://pkg.go.dev/github.com/theHamdiz/it)\n\n---\n\nNow go write some code that might actually work, or not!\n\n\u003e *No functions were harmed in the making of this package*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthehamdiz%2Fit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthehamdiz%2Fit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthehamdiz%2Fit/lists"}