github.com/songzhibin97/gkit@v1.2.13/README.md (about) 1 # GKIT 2 3 ``` 4 _____/\\\\\\\\\\\\__/\\\________/\\\__/\\\\\\\\\\\__/\\\\\\\\\\\\\\\_ 5 ___/\\\//////////__\/\\\_____/\\\//__\/////\\\///__\///////\\\/////__ 6 __/\\\_____________\/\\\__/\\\//_________\/\\\___________\/\\\_______ 7 _\/\\\____/\\\\\\\_\/\\\\\\//\\\_________\/\\\___________\/\\\_______ 8 _\/\\\___\/////\\\_\/\\\//_\//\\\________\/\\\___________\/\\\_______ 9 _\/\\\_______\/\\\_\/\\\____\//\\\_______\/\\\___________\/\\\_______ 10 _\/\\\_______\/\\\_\/\\\_____\//\\\______\/\\\___________\/\\\_______ 11 _\//\\\\\\\\\\\\/__\/\\\______\//\\\__/\\\\\\\\\\\_______\/\\\_______ 12 __\////////////____\///________\///__\///////////________\///________ 13 ``` 14 15 ##### Translate to: [简体中文](README_zh.md) 16 17 # Project Description 18 Dedicated to providing microservices and monolithic services of the availability of a collection of basic component tools, drawing on some of the best open source projects such as : `kratos`, `go-kit`, `mosn`, `sentinel`, `gopkg` ... We hope you will support us! 19 20 # Directory structure 21 ```shell 22 ├── cache (builds cache-related components) 23 ├── buffer (provides byte array reuse and io buffer wrapping) 24 ├── mbuffer (buffer-like implementation) 25 ├── local_cache (provides local key-value wrapper implementation for building local caches) 26 ├── singleflight (provides prevention of duplicate tasks in high concurrency situations, generally used to fill cache miss scenarios) 27 ├── coding (provides object serialization/deserialization interface, provides json, proto, xml, yaml instance methods) 28 ├── concurrent (best practices for using channels in concurrency) 29 ├── fan_in (fan-in pattern, commonly used with multiple producers and one consumer in the producer-consumer model) 30 ├── fan_out (fan-out mode, often used with a producer-consumer model where there are multiple producers and multiple consumers) 31 ├── or_done (a concurrency scenario in which any one task is returned immediately after completion) 32 ├── orderly (keep orderly completion even in concurrent scenarios) 33 ├── map_reduce 34 ├── stream (provides data production stream encapsulation, and implementation of processing streams) 35 ├── pipeline (concurrency becomes serial) 36 ├── container (containerized component, providing groups, pools, queues) 37 ├── group (provides a lazy loading mode for containers, similar to sync.Pool, which uses a key to get the corresponding container instance when used, or generates it if it doesn\'t exist) 38 ├── pool (provides a wrapped abstraction of pool, and an implementation of the interface using lists) 39 ├── queue 40 ├── codel (implements a controlled delay algorithm for columns, and sanctions backlogged tasks) 41 ├── delayed (delayed tasks - standalone version) 42 ├── distributed (distributed tasks, provides standardized interfaces and corresponding implementations for redis, mysql, pgsql, mongodb) 43 ├── downgrade (fusion downgrade related components) 44 ├── egroup (errgroup, controls component lifecycle) 45 ├── encrypt (Encryption encapsulation, protection padkey complement) 46 ├── errors (grpc error handling) 47 ├── gctuner (pre go1.19 gc optimization tool) 48 ├── generator (number generator, snowflake) 49 ├── goroutine (provide goroutine pools, control goroutine spikes) 50 ├── log (interface logging, use logging component to access) 51 ├── metrics (interface to metrics) 52 ├── middleware (middleware interface model definition) 53 ├── net (network related encapsulation) 54 ├── tcp 55 ├── options (option model interfacing) 56 ├── overload (server adaptive protection, provides bbr interface, monitors deployed server status to select traffic release, protects server availability) 57 ├── bbr (adaptive flow limiting) 58 ├── page_token (google aip next token implementation) 59 ├── parser (file parsing, proto<->go mutual parsing) 60 ├── parseGo (parses go to generate pb) 61 ├── parsePb (parses pb to generate go) 62 ├── registry (service discovery interfacing, google sre subset implementation) 63 ├── restrictor (restrict flow, provide token bucket and leaky bucket interface wrappers) 64 ├── client_throttling (client throttling) 65 ├── rate 66 ├── ratelimite 67 ├── structure (common data structure) 68 ├── hashset (hash tables) 69 ├── lscq (lock-free unbounded queue, supports arm) 70 ├── skipmap 71 ├── skipset 72 ├── zset 73 ├── sync 74 ├── cpu (Get system information for Linux, including cpu mains, cpu usage, etc.) 75 ├── fastrand (random numbers) 76 ├── goid (get goroutine id) 77 ├── mutex (provides trylock, reentrant lock and token reentrant lock) 78 ├── nanotime (timestamp optimization) 79 ├── once (a more powerful implementation of once, set the once function to return an error, and retry if it fails) 80 ├── queue (lock-free queue) 81 ├── safe (underlying string, slice structure) 82 ├── stringx (enhanced version of string) 83 ├── syncx (sync enhancement) 84 ├── xxhash3 85 ├── ternary (ternary expressions) 86 ├── timeout (timeout control, full link protection, provides some encapsulated implementation of database processing time) 87 ├── ctime (link timeout control) 88 ├── c_json (adapt to database json types) 89 ├── d_time (adapts to database to store time only) 90 ├── date (Adapts database to store dates only) 91 ├── date_struct (Adapts database to store dates only) 92 ├── datetime (adapter database stores datetime) 93 ├── datetime_struct (adapter database stores datetime) 94 ├── stamp (adapter database stores timestamps) 95 ├── human (provides visual time spacing) 96 ├── tools 97 ├── bind (binding tool, often used with the gin framework to customize the bound data, e.g. binding both query and json) 98 ├── deepcopy (deep copy) 99 ├── float (floating point truncation tool) 100 ├── match (base matcher, match on wildcards) 101 ├── pointer (pointer tool) 102 ├── pretty (formatting json) 103 ├── reflect2value (basic field mapping) 104 ├── rand_string (random strings) 105 ├── vto (assignment of functions with the same type, hands free, usually used for vo->do object conversions) 106 ├── vtoPlus (adds plus support for field, tag and default value binding) 107 ├── trace (link tracing) 108 ├── watching (monitor cpu, mum, gc, goroutine and other metrics, automatically dump pprof metrics in case of fluctuations) 109 └── window (sliding window, supports multi-data type metrics window collection) 110 111 ``` 112 113 # Download and use 114 ```shell 115 go get github.com/songzhibin97/gkit 116 ``` 117 118 119 ## Introduction to the use of components 120 ## cache 121 122 Cache-related components 123 > buffer & mbuffer provide similar functionality, buffer has more encapsulation and implements some interfaces to io, while mbuffer is just a memory cache; it is more suitable for short and frequent life cycles. 124 > local_cache provides a local data cache, and also has some expiry mechanisms, you can set the expiry time, and regularly clean up the expired data, but he is now older, if needed there is a generic version https://github.com/songzhibin97/go-baseutils/blob/main/ app/bcache 125 > singleflight wraps golang.org/x/sync/singleflight to prevent the effects of changes. 126 127 128 ### buffer pool 129 ```go 130 package main 131 132 import ( 133 "fmt" 134 "github.com/songzhibin97/gkit/cache/buffer" 135 ) 136 137 func main() { 138 // Byte reuse 139 140 // size 2^6 - 2^18 141 // return an integer multiple of 2 rounded upwards cap, len == size 142 // Any other special or expanded during runtime will be cleared 143 slice := buffer.GetBytes(1024) 144 fmt.Println(len(*slice), cap(*slice)) // 1024 1024 145 146 // Recycle 147 // Note: no further references are allowed after recycling 148 buffer.PutBytes(slice) 149 150 // IOByte reuse 151 152 // io buffer.IoBuffer interface 153 GetIoPool(1024) 154 155 // If an object has already been recycled, referring to the recycled object again will trigger an error 156 err := buffer.PutIoPool(io) 157 if err != nil { 158 // Handle the error 159 } 160 } 161 ``` 162 163 164 ### local_cache 165 ```go 166 package local_cache 167 168 import ( 169 "github.com/songzhibin97/gkit/cache/buffer" 170 "log" 171 ) 172 173 var ch Cache 174 175 func ExampleNewCache() { 176 // default configuration 177 // ch = NewCache() 178 179 // Optional configuration options 180 181 // Set the interval time 182 // SetInternal(interval time.Duration) 183 184 // Set the default timeout 185 // SetDefaultExpire(expire time.Duration) 186 187 // Set the cycle execution function, the default (not set) is to scan the global to clear expired k 188 // SetFn(fn func()) 189 190 // Set the capture function to be called after the deletion is triggered, the set capture function will be called back after the data is deleted 191 // SetCapture(capture func(k string, v interface{})) 192 193 // Set the initialization of the stored member object 194 // SetMember(m map[string]Iterator) 195 196 ch = NewCache(SetInternal(1000). 197 SetDefaultExpire(10000). 198 SetCapture(func(k string, v interface{}) { 199 log.Println(k, v) 200 })) 201 } 202 203 func ExampleCacheStorage() { 204 // Set adds cache and overwrites it whether it exists or not 205 ch.Set("k1", "v1", DefaultExpire) 206 207 // SetDefault overrides whether or not it exists 208 // Default function mode, default timeout is passed in as the default time to create the cache 209 ch.SetDefault("k1", 1) 210 211 // SetNoExpire 212 // partial function mode, default timeout is never expired 213 ch.SetNoExpire("k1", 1.1) 214 215 // Add the cache and throw an exception if it exists 216 err := ch.Add("k1", nil, DefaultExpire) 217 CacheErrExist(err) // true 218 219 // Replace throws an error if it is set or not 220 err = ch.Replace("k2", make(chan struct{}), DefaultExpire) 221 CacheErrNoExist(err) // true 222 } 223 224 func ExampleGet() { 225 // Get the cache based on the key to ensure that kv is removed within the expiration date 226 v, ok := ch.Get("k1") 227 if !ok { 228 // v == nil 229 } 230 _ = v 231 232 // GetWithExpire gets the cache based on the key and brings up the timeout 233 v, t, ok := ch.GetWithExpire("k1") 234 if !ok { 235 // v == nil 236 } 237 // if the timeout is NoExpire t.IsZero() == true 238 if t.IsZero() { 239 // No timeout is set 240 } 241 242 // Iterator returns all valid objects in the cache 243 mp := ch.Iterator() 244 for s, iterator := range mp { 245 log.Println(s, iterator) 246 } 247 248 // Count returns the number of members 249 log.Println(ch.Count()) 250 } 251 252 func ExampleIncrement() { 253 ch.Set("k3", 1, DefaultExpire) 254 ch.Set("k4", 1.1, DefaultExpire) 255 // Increment adds n to the value corresponding to k n must be a number type 256 err := ch.Increment("k3", 1) 257 if CacheErrExpire(err) || CacheErrExist(CacheTypeErr) { 258 // Not set successfully 259 } 260 _ = ch.IncrementFloat("k4", 1.1) 261 262 // If you know the exact type of k to set you can also use the type-determining increment function 263 // ch.IncrementInt(k string, v int) 264 // ... 265 // IncrementFloat32(k string, v flot32) // ch. 266 // ... 267 268 // Decrement the same 269 } 270 271 func ExampleDelete() { 272 // Delete triggers the not-or function if capture is set 273 ch.Delete("k1") 274 275 // DeleteExpire Deletes all expired keys, the default capture is to execute DeleteExpire() 276 ch.DeleteExpire() 277 } 278 279 func ExampleChangeCapture() { 280 // Provides a way to change the capture function on the fly 281 // ChangeCapture 282 ch.ChangeCapture(func(k string, v interface{}) { 283 log.Println(k, v) 284 }) 285 } 286 287 func ExampleSaveLoad() { 288 // Write to a file using go's proprietary gob protocol 289 290 io := buffer.NewIoBuffer(1000) 291 292 // Save pass in a w io.Writer argument to write the member members of the cache to w 293 _ = ch.Save(io) 294 295 // SaveFile pass in a path to write to a file 296 _ = ch.SaveFile("path") 297 298 // Load pass in an r io.Reader object read from r and write back to member 299 _ = ch.Load(io) 300 301 // LoadFile pass in path to read the contents of the file 302 _ = ch.LoadFile("path") 303 } 304 305 func ExampleFlush() { 306 // Flush to free member members 307 ch.Flush() 308 } 309 310 func ExampleShutdown() { 311 // Shutdown frees the object 312 ch.Shutdown() 313 } 314 ``` 315 316 ### singleflight 317 318 Merge back to source 319 ```go 320 package main 321 322 import ( 323 "github.com/songzhibin97/gkit/cache/singleflight" 324 ) 325 326 // getResources: Generally used to go to the database and fetch data 327 func getResources() (interface{}, error) { 328 return "test", nil 329 } 330 331 // cache: populate the cache with data 332 func cache(v interface{}) { 333 return 334 } 335 336 func main() { 337 f := singleflight.NewSingleFlight() 338 339 // Synchronize. 340 v, err, _ := f.Do("test1", func() (interface{}, error) { 341 // Get resources 342 return getResources() 343 }) 344 if err != nil { 345 // Handle the error 346 } 347 // store to buffer 348 // v is the fetched resource 349 cache(v) 350 351 // asynchronously 352 ch := f.DoChan("test2", func() (interface{}, error) { 353 // Get resources 354 return getResources() 355 }) 356 357 // Wait for the resource to be fetched, then return the result via channel 358 result := <-ch 359 if result.Err != nil { 360 // Handle the error 361 } 362 363 // store to buffer 364 // result.Val is the fetched resource 365 cache(result.Val) 366 367 // try to cancel 368 f.Forget("test2") 369 } 370 ``` 371 372 373 ## coding 374 > Object serialization deserialization interface and instance encapsulation, just import anonymous, such as json `_ "github.com/songzhibin97/gkit/coding/json"` You can also implement the corresponding interface, after registration, the benefit is to control the global serialization object and the use of library unity 375 376 ```go 377 package main 378 379 import ( 380 "fmt" 381 "github.com/songzhibin97/gkit/coding" 382 _ "github.com/songzhibin97/gkit/coding/json" // Be sure to import ahead of time!!! 383 ) 384 385 func main() { 386 t := struct { 387 Gkit string 388 Lever int 389 }{"Gkit", 200} 390 fmt.Println(coding.GetCode("json").Name()) 391 GetCode("json").Marshal(t) 392 if err != nil { 393 fmt.Println(err) 394 return 395 } 396 fmt.Println(string(data)) // {"Gkit": "Gkit", "Lever":200} 397 v := struct { 398 Gkit string 399 Lever int 400 }{} 401 coding.GetCode("json").Unmarshal(data,&v) 402 fmt.Println(v) // { Gkit 200} 403 } 404 ``` 405 406 ## concurrent 407 408 > Best practices for channel in concurrency, including fan_in,fan_out,map_reduce,or_done,orderly,pipeline,stream,generic version can be found at https://github.com/songzhibin97/go-baseutils/tree/main/app/bconcurrent 409 410 ## container 411 412 > Pool, but you can customize the creation function and replace the initialization function. 413 > pool pooling object, through the configuration can set the maximum number of connections and the number of waiting connections, synchronous asynchronous acquisition of connections, and connection life cycle management, you can customize the creation function, and replace the initialization function 414 > codel implement codel algorithm, can be used to limit the flow, and fuse 415 416 ### group 417 418 Lazy loading containers 419 ```go 420 package main 421 422 import ( 423 "fmt" 424 "github.com/songzhibin97/gkit/container/group" 425 ) 426 427 func createResources() interface{} { 428 return map[int]int{1: 1, 2: 2} 429 } 430 431 func createResources2() interface{} { 432 return []int{1, 2, 3} 433 } 434 435 func main() { 436 // Like sync.Pool 437 // initialize a group 438 g := group.NewGroup(createResources) 439 440 // If the key does not exist call the function passed in by NewGroup to create resources 441 // If it exists, return the information about the created resource 442 v := g.Get("test") 443 fmt.Println(v) // map[1:1 2:2] 444 v.(map[int]int)[1] = 3 445 fmt.Println(v) // map[1:3 2:2] 446 v2 := g.Get("test") 447 fmt.Println(v2) // map[1:3 2:2] 448 449 // ReSet resets the initialization function and clears the cached key 450 g.ReSet(createResources2) 451 v3 := g.Get("test") 452 fmt.Println(v3) // []int{1,2,3} 453 454 // Clear the cached buffer 455 g.Clear() 456 } 457 ``` 458 459 ### pool 460 461 Similar to a resource pool 462 ```go 463 package main 464 465 import ( 466 "context" 467 "fmt" 468 "github.com/songzhibin97/gkit/container/pool" 469 "time" 470 ) 471 472 var p pool.Pool 473 474 type mock map[string]string 475 476 func (m *mock) Shutdown() error { 477 return nil 478 } 479 480 // getResources: gets resources, returns a resource object that needs to implement the IShutdown interface for resource recycling 481 func getResources(context.Context) (pool.IShutdown, error) { 482 return &mock{"mockKey": "mockValue"}, nil 483 } 484 485 func main() { 486 // pool.NewList(options ...) 487 // default configuration 488 // p = pool.NewList() 489 490 // Optional configuration options 491 492 // Set the number of Pool connections, if == 0 then no limit 493 // pool.SetActive(100) 494 495 // Set the maximum number of free connections 496 // pool.SetIdle(20) 497 498 // Set idle wait time 499 // pool.SetIdleTimeout(time.Second) 500 501 // Set the expected wait 502 // pool.SetWait(false,time.Second) 503 504 // Customize the configuration 505 p = pool.NewList( 506 pool.SetActive(100). 507 pool.SetIdle(20). 508 pool.SetIdleTimeout(time.Second). 509 SetIdleTimeout(time.Second), pool.SetWait(false, time.Second)) 510 511 // New needs to be instantiated, otherwise it will not get the resource in pool. 512 p.NewQueue(getResources) 513 514 v, err := p.Get(context.TODO()) 515 if err != nil { 516 // Handle the error 517 } 518 fmt.Println(v) // &map[mockKey:mockValue] 519 520 // Put: Resource recovery 521 // forceClose: true internally help you call Shutdown to recycle, otherwise determine if it is recyclable and mount it on a list 522 err = p.Put(context.TODO(), v, false) 523 if err != nil { 524 // handle the error 525 } 526 527 // Shutdown reclaims resources, shutting down all resources 528 _ = p.Shutdown() 529 } 530 ``` 531 532 533 ### queue 534 535 codel implementation 536 537 ```go 538 package main 539 540 import ( 541 "context" 542 "fmt" 543 "github.com/songzhibin97/gkit/container/queue/codel" 544 "github.com/songzhibin97/gkit/overload/bbr" 545 ) 546 547 func main() { 548 queue := codel.NewQueue(codel.SetTarget(40), codel.SetInternal(1000)) 549 550 // start reflects CoDel state information 551 start := queue.Stat() 552 fmt.Println(start) 553 554 go func() { 555 // where the actual consumption takes place 556 queue.Pop() 557 }() 558 if err := queue.Push(context.TODO()); err != nil { 559 if err == bbr.LimitExceed { 560 // todo handles overload protection errors 561 } else { 562 // todo handles other errors 563 } 564 } 565 } 566 ``` 567 568 ## delayed 569 570 > Stand-alone version of the delay task, using the quadruple heap for implementation, you can customize the monitoring signal, as well as the monitoring time, and the number of work co-processes 571 572 ```go 573 package main 574 575 import "github.com/songzhibin97/gkit/delayed" 576 577 type mockDelayed struct { 578 exec int64 579 } 580 581 func (m mockDelayed) Do() { 582 } 583 584 func (m mockDelayed) ExecTime() int64 { 585 return m.exec 586 } 587 588 func (m mockDelayed) Identify() string { 589 return "mock" 590 } 591 592 func main() { 593 // Create a delayed object 594 // delayed.SetSingle() sets the monitor signal 595 // delayed.SetSingleCallback() set the signal callback 596 // delayed.SetWorkerNumber() sets the worker concurrently 597 // delayed.SetCheckTime() Set the monitoring time 598 n := delayed.NewDispatchingDelayed() 599 600 // add a delayed task 601 n.AddDelayed(mockDelayed{exec: 1}) 602 603 // Force a refresh 604 n.Refresh() 605 606 // Close 607 n.Close() 608 } 609 610 ``` 611 612 ## distributed 613 614 > Distributed tasks, currently supports db(gorm), mongodb, redis on the backend, redis on the scheduling side, redis on the distributed locking side, including retry mechanisms, and deferred tasks 615 616 ## downgrade 617 618 Meltdown downgrade 619 620 ```go 621 // Same as github.com/afex/hystrix-go, but in an abstract wrapper to avoid the impact of upgrades on the service 622 package main 623 624 import ( 625 "context" 626 "github.com/afex/hystrix-go/hystrix" 627 "github.com/songzhibin97/gkit/downgrade" 628 ) 629 630 var fuse downgrade.Fuse 631 632 type RunFunc = func() error 633 type FallbackFunc = func(error) error 634 type RunFuncC = func(context.Context) error 635 type FallbackFuncC = func(context.Context, error) error 636 637 var outCH = make(chan struct{}, 1) 638 639 func mockRunFunc() RunFunc { 640 return func() error { 641 outCH <- struct{}{} 642 return nil 643 } 644 } 645 646 func mockFallbackFunc() FallbackFunc { 647 return func(err error) error { 648 return nil 649 } 650 } 651 652 func mockRunFuncC() RunFuncC { 653 return func(ctx context.Context) error { 654 return nil 655 } 656 } 657 658 func mockFallbackFuncC() FallbackFuncC { 659 return func(ctx context.Context, err error) error { 660 return nil 661 } 662 } 663 664 func main() { 665 // Get a fuse 666 fuse = downgrade.NewFuse() 667 668 // Leave ConfigureCommand unset and go to the default configuration 669 // hystrix.CommandConfig{} set the parameters 670 fuse.ConfigureCommand("test", hystrix.CommandConfig{}) 671 672 // Do: execute func() error synchronously, no timeout control until it returns. 673 // if return error ! = nil then FallbackFunc is triggered to downgrade 674 err := fuse.Do("do", mockRunFunc(), mockFallbackFunc()) 675 if err != nil { 676 // Handle the error 677 } 678 679 // Go: asynchronous execution Return channel 680 ch := fuse.Go("go", mockRunFunc(), mockFallbackFunc()) 681 select { 682 case err = <-ch: 683 // Handle the error 684 case <-outCH: 685 break 686 } 687 688 // GoC: Do/Go actually ends up calling GoC, the Do master handles the asynchronous process 689 // GoC can be passed into context to ensure link timeout control 690 fuse.GoC(context.TODO(), "goc", mockRunFuncC(), mockFallbackFuncC()) 691 } 692 ``` 693 694 ## egroup 695 696 > ErrorGroup, compared with sync.ErrorGroup, adds a fault tolerance mechanism to prevent wild goroutine panic resulting in abnormal system exit 697 698 ```go 699 // errorGroup 700 // Cascade control, if a component has an error, all components in the group will be notified to exit 701 // Declare lifecycle management 702 703 package main 704 705 import ( 706 "context" 707 "github.com/songzhibin97/gkit/egroup" 708 "os" 709 "syscall" 710 "time" 711 ) 712 713 var admin *egroup.LifeAdmin 714 715 func mockStart() func(ctx context.Context) error { 716 return nil 717 } 718 719 func mockShutdown() func(ctx context.Context) error { 720 return nil 721 } 722 723 type mockLifeAdminer struct{} 724 725 func (m *mockLifeAdminer) Start(ctx context.Context) error { 726 return nil 727 } 728 729 func (m *mockLifeAdminer) Shutdown(ctx context.Context) error { 730 return nil 731 } 732 733 func main() { 734 // Default configuration 735 // admin = egroup.NewLifeAdmin() 736 737 // Optional configuration options 738 739 // set the start timeout 740 741 // <= 0 no start timeout, note that shutdown notifications should be handled at shutdown 742 // egroup.SetStartTimeout(time.Second) 743 744 // Set the shutdown timeout 745 // <=0 no start timeout 746 // egroup.SetStopTimeout(time.Second) 747 748 // Set the set of signals, and the functions to handle them 749 // egroup.SetSignal(func(lifeAdmin *LifeAdmin, signal os.Signal) { 750 // return 751 // }, signal...) 752 753 admin = egroup.NewLifeAdmin(egroup.SetStartTimeout(time.Second), egroup.SetStopTimeout(time.Second), 754 egroup.SetSignal(func(a *egroup.LifeAdmin, signal os.Signal) { 755 switch signal { 756 case syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT: 757 a.Shutdown() 758 default: 759 } 760 })) 761 762 // Add via struct 763 admin.Add(egroup.Member{ 764 Start: mockStart(), 765 Shutdown: mockShutdown(), 766 }) 767 768 // Adapted via interface 769 admin.AddMember(&mockLifeAdminer{}) 770 771 // Start 772 defer admin.Shutdown() 773 if err := admin.Start(); err != nil { 774 // Handle errors 775 // normal start will hold main 776 } 777 } 778 779 func Demo() { 780 // Full demo 781 var _admin = egroup.NewLifeAdmin() 782 783 srv := &http.Server{ 784 Addr: ":8080", 785 } 786 // Add a task 787 _admin.Add(egroup.Member{ 788 Start: func(ctx context.Context) error { 789 fmt.Println("http start") 790 return goroutine.Delegate(ctx, -1, func(ctx context.Context) error { 791 return srv.ListenAndServe() 792 }) 793 }, 794 Shutdown: func(ctx context.Context) error { 795 fmt.Println("http shutdown") 796 return srv.Shutdown(context.Background()) 797 }, 798 }) 799 // _admin.Start() start 800 fmt.Println("error", _admin.Start()) 801 defer _admin.Shutdown() 802 } 803 804 ``` 805 806 ## encrypt 807 808 > Encryption encapsulation, protection padkey complement 809 810 ## errors 811 812 Wrapping some error handling 813 814 ```go 815 package main 816 817 import ( 818 "fmt" 819 "net/http" 820 "time" 821 822 "github.com/songzhibin97/gkit/errors" 823 ) 824 func main() { 825 err := errors.Errorf(http.StatusBadRequest, "reason", "carrying message %s", "test") 826 err2 := err.AddMetadata(map[string]string{"time": time.Now().String()}) // Carry meta information 827 // err is the original error err2 is the error with meta information 828 fmt.Println(errors.Is(err,err2)) // ture 829 // err2 can be parsed to get more information 830 fmt.Println(err2.Metadata["time"]) // meta 831 } 832 ```` 833 834 ## gctuner 835 836 > go pre 1.19 gc optimizer 837 838 ```go 839 840 package main 841 842 import "github.com/songzhibin97/gkit/gctuner" 843 844 func main() { 845 // Get mem limit from the host machine or cgroup file. 846 limit := 4 * 1024 * 1024 * 1024 847 threshold := uint64(float64(limit) * 0.7) 848 849 gctuner.Tuning(threshold) 850 851 // Friendly input 852 gctuner.TuningWithFromHuman("1g") 853 854 // Auto 855 // There may be problems with multiple services in one pod. 856 gctuner.TuningWithAuto(false) // Is it a container? Incoming Boolean 857 } 858 ``` 859 860 ## generator 861 862 Generator 863 864 ### snowflake 865 866 Snowflake algorithm 867 868 ```go 869 package main 870 871 import ( 872 "fmt" 873 "github.com/songzhibin97/gkit/generator" 874 "time" 875 ) 876 877 func main() { 878 ids := generator.NewSnowflake(time.Now(), 1) 879 nid, err := ids.NextID() 880 if err != nil { 881 // Handle the error 882 } 883 fmt.Println(nid) 884 } 885 886 ``` 887 888 ## goroutine 889 890 > Pooling, control exceptions caused by wild goroutine panic, can set maximum capacity, idle time, patrol time, stop timeout, log objects 891 892 ```go 893 package main 894 895 import ( 896 "context" 897 "fmt" 898 "github.com/songzhibin97/gkit/goroutine" 899 "time" 900 ) 901 902 var gGroup goroutine.GGroup 903 904 func mockFunc() func() { 905 return func() { 906 fmt.Println("ok") 907 } 908 } 909 910 func main() { 911 // Default configuration 912 // gGroup = goroutine.NewGoroutine(context.TODO()) 913 914 // Optional configuration options 915 916 // set the stop timeout time 917 // goroutine.SetStopTimeout(time.Second) 918 919 // Set the log object 920 // goroutine.SetLogger(&testLogger{}) 921 922 // Set the maximum pool size 923 // goroutine.SetMax(100) 924 925 gGroup = goroutine.NewGoroutine(context.TODO(), 926 goroutine.SetStopTimeout(time.Second), 927 goroutine.SetMax(100), 928 ) 929 930 // Add a task 931 if !gGroup.AddTask(mockFunc()) { 932 // Adding a task failed 933 } 934 935 // Add a task with timeout control 936 if !gGroup.AddTaskN(context.TODO(), mockFunc()) { 937 // Failed to add task 938 } 939 940 // Modify the pool maximum size 941 gGroup.ChangeMax(1000) 942 943 // Recycle resources 944 _ = gGroup.Shutdown() 945 } 946 ``` 947 948 ## log 949 950 Logging related 951 952 ```go 953 package main 954 955 import ( 956 "fmt" 957 "github.com/songzhibin97/gkit/log" 958 ) 959 960 type testLogger struct{} 961 962 func (l *testLogger) Print(kv ...interface{}) { 963 fmt.Println(kv...) 964 } 965 966 func main() { 967 logs := log.NewHelper(log.DefaultLogger) 968 logs.Debug("debug", "v") 969 logs.Debugf("%s,%s", "debugf", "v") 970 logs.Info("Info", "v") 971 logs.Infof("%s,%s", "infof", "v") 972 logs.Warn("Warn", "v") 973 logs.Warnf("%s,%s", "warnf", "v") 974 logs.Error("Error", "v") 975 logs.Errorf("%s,%s", "errorf", "v") 976 /* 977 [debug] message=debugv 978 [debug] message=debugf,v 979 [Info] message=Infov 980 [Info] message=infof,v 981 [Warn] message=Warnv 982 [Warn] message=warnf,v 983 [Error] message=Errorv 984 [Error] message=errorf,v 985 */ 986 987 logger := log.DefaultLogger 988 logger = log.With(logger, "ts", log.DefaultTimestamp, "caller", log.DefaultCaller) 989 logger.Log(log.LevelInfo, "msg", "helloworld") 990 // [Info] ts=2021-06-10T13:41:35+08:00 caller=main.go:8 msg=helloworld 991 } 992 ``` 993 994 ## metrics 995 996 Provides a metrics interface for implementing monitoring configurations 997 ```go 998 package main 999 1000 type Counter interface { 1001 With(lvs ...string) Counter 1002 Inc() 1003 Add(delta float64) 1004 } 1005 1006 // Gauge is metrics gauge. 1007 type Gauge interface { 1008 With(lvs ...string) Gauge 1009 Set(value float64) 1010 Add(delta float64) 1011 Sub(delta float64) 1012 } 1013 1014 // Observer is metrics observer. 1015 type Observer interface { 1016 With(lvs ...string) Observer 1017 Observe(float64) 1018 } 1019 ``` 1020 1021 ## middleware 1022 1023 Middleware interface model definition 1024 ```go 1025 package main 1026 1027 import ( 1028 "context" 1029 "fmt" 1030 "github.com/songzhibin97/gkit/middleware" 1031 ) 1032 1033 func annotate(s string) middleware.MiddleWare { 1034 return func(next middleware.Endpoint) middleware.Endpoint { 1035 return func(ctx context.Context, request interface{}) (interface{}, error) { 1036 fmt.Println(s, "pre") 1037 defer fmt.Println(s, "post") 1038 return next(ctx, request) 1039 } 1040 } 1041 } 1042 1043 func myEndpoint(context.Context, interface{}) (interface{}, error) { 1044 fmt.Println("my endpoint!") 1045 return struct{}{}, nil 1046 } 1047 1048 var ( 1049 ctx = context.Background() 1050 req = struct{}{} 1051 ) 1052 1053 func main() { 1054 e := middleware.Chain( 1055 annotate("first"), 1056 annotate("second"), 1057 annotate("third"), 1058 )(myEndpoint) 1059 1060 if _, err := e(ctx, req); err != nil { 1061 panic(err) 1062 } 1063 // Output. 1064 // first pre 1065 // second pre 1066 // third pre 1067 // my endpoint! 1068 // third post 1069 // second post 1070 // first post 1071 } 1072 ``` 1073 1074 ## net 1075 1076 Network related encapsulation 1077 1078 ### tcp 1079 ```go 1080 // Send data to the other side, with a retry mechanism 1081 Send(data []byte, retry *Retry) error 1082 1083 // Accept data 1084 // length == 0 Read from Conn once and return immediately 1085 // length < 0 Receive all data from Conn and return it until there is no more data 1086 // length > 0 Receive the corresponding data from Conn and return it 1087 Recv(length int, retry *Retry) ([]byte, error) 1088 1089 // Read a line of '\n' 1090 RecvLine(retry *Retry) ([]byte, error) 1091 1092 // Read a link that has timed out 1093 RecvWithTimeout(length int, timeout time.Duration, retry *Retry) ([]byte, error) 1094 1095 // Write data to a link that has timed out 1096 SendWithTimeout(data []byte, timeout time.Duration, retry *Retry) error 1097 1098 // Write data and read back 1099 SendRecv(data []byte, length int, retry *Retry) ([]byte, error) 1100 1101 // Write data to and read from a link that has timed out 1102 SendRecvWithTimeout(data []byte, timeout time.Duration, length int, retry *Retry) ([]byte, error) 1103 ``` 1104 1105 ## options 1106 1107 Options mode interface 1108 1109 1110 ## overload 1111 > Overload protection, internal current limiting using bbr algorithm 1112 1113 **general use** 1114 1115 ```go 1116 package main 1117 1118 import ( 1119 "context" 1120 "github.com/songzhibin97/gkit/overload" 1121 "github.com/songzhibin97/gkit/overload/bbr" 1122 ) 1123 1124 func main() { 1125 // Common use 1126 1127 // Create the Group first 1128 group := bbr.NewGroup() 1129 // If it doesn't exist, it will be created 1130 limiter := group.Get("key") 1131 f, err := limiter.Allow(context.TODO()) 1132 if err != nil { 1133 // means it is overloaded and the service is not allowed to access it 1134 return 1135 } 1136 // Op: the actual operation type of the traffic write-back record indicator 1137 f(overload.DoneInfo{Op: overload.Success}) 1138 } 1139 ``` 1140 1141 **Middleware application** 1142 1143 ```go 1144 package main 1145 1146 import ( 1147 "context" 1148 "github.com/songzhibin97/gkit/overload" 1149 "github.com/songzhibin97/gkit/overload/bbr" 1150 ) 1151 1152 func main() { 1153 // Common use 1154 1155 // Create the Group first 1156 group := bbr.NewGroup() 1157 // If it doesn't exist, it will be created 1158 limiter := group.Get("key") 1159 f, err := limiter.Allow(context.TODO()) 1160 if err != nil { 1161 // means it is overloaded and the service is not allowed to access it 1162 return 1163 } 1164 // Op: the actual operation type of the traffic write-back record indicator 1165 f(overload.DoneInfo{Op: overload.Success}) 1166 1167 // Create Group middleware 1168 middle := bbr.NewLimiter() 1169 1170 // in the middleware 1171 // The ctx carries these two configurable valid data 1172 // You can get the limiter type via the ctx.Set 1173 1174 // Configure to get the limiter type, you can get different limiter according to different api 1175 ctx := context.WithValue(context.TODO(), bbr.LimitKey, "key") 1176 1177 // Configurable to report success or not 1178 // must be of type overload. 1179 ctx = context.WithValue(ctx, bbr.LimitOp, overload.Success) 1180 1181 _ = middle 1182 } 1183 ``` 1184 1185 ## page_token 1186 > https://google.aip.dev/158 Google Pagination 1187 > The options mode allows you to configure a custom maximum page value, maximum number of elements per page, set the encryption key, and expiration time, page_token to effectively prevent crawlers and page flip attacks, and to limit the interface concurrency. 1188 1189 ```go 1190 package main 1191 1192 import "github.com/songzhibin97/gkit/page_token" 1193 1194 func main() { 1195 n := NewTokenGenerate("test") // Unique identification of the resource, and the option to pass the above 1196 // 10000 is the total number 1197 // Generate page_token 1198 // start - end start and end address, tk is next_token 1199 start, end, tk, err := n.ProcessPageTokens(10000, 100, "") // 0,100, tk 1200 start, end, ntk, err := n.ProcessPageTokens(10000, 100, tk) // 100,200,ntk 1201 n.GetIndex(ntk) // 200 1202 } 1203 ``` 1204 1205 ## parser 1206 1207 Provides `.go` file to `.pb` and `.pb` to `.go` 1208 `.go` files to `.pb` are more feature-rich, for example, providing spot staking code injection and de-duplication recognition 1209 1210 ```go 1211 package main 1212 1213 import ( 1214 "fmt" 1215 "github.com/songzhibin97/gkit/parse/parseGo" 1216 "github.com/songzhibin97/gkit/parse/parsePb" 1217 ) 1218 1219 func main() { 1220 pgo, err := parseGo.ParseGo("gkit/parse/demo/demo.api") 1221 if err != nil { 1222 panic(err) 1223 } 1224 r := pgo.(*parseGo.GoParsePB) 1225 for _, note := range r.Note { 1226 fmt.Println(note.Text, note.Pos(), note.End()) 1227 } 1228 // Output the string, if you need to import the file yourself 1229 fmt.Println(r.Generate()) 1230 1231 // Pile injection 1232 _ = r.PileDriving("", "start", "end", "var _ = 1") 1233 1234 // Dismounting 1235 _ = r.PileDismantle("var _ = 1") 1236 1237 ppb, err := parsePb.ParsePb("GKit/parse/demo/test.proto") 1238 if err != nil { 1239 panic(err) 1240 } 1241 // Output the string, if you need to import the file yourself 1242 fmt.Println(ppb.Generate()) 1243 } 1244 ``` 1245 1246 ## registry 1247 1248 > Provides a generic interface for registration discovery, external dependencies using the generic interface, and a fixed instance structure 1249 > Service discovery provides a variety of algorithms, from the common subset algorithm to the latest rock_steadier_subset(https://dl.acm.org/doi/10.1145/3570937) 1250 1251 1252 ## restrictor 1253 1254 flow limiter 1255 1256 ### rate 1257 1258 leakage bucket 1259 1260 ```go 1261 package main 1262 1263 import ( 1264 "context" 1265 rate2 "github.com/songzhibin97/gkit/restrictor/rate" 1266 "golang.org/x/time/rate" 1267 "time" 1268 ) 1269 1270 func main() { 1271 // The first argument is r Limit, which represents how many tokens can be generated into the Token bucket per second; Limit is actually an alias for float64 1272 // The second argument is b int. b represents the size of the Token bucket. 1273 // limit := Every(100 * time.Millisecond). 1274 // limiter := rate.NewLimiter(limit, 4) 1275 // The above means putting a Token in the bucket every 100ms, which essentially means generating 10 a second. 1276 1277 // rate: golang.org/x/time/rate 1278 limiter := rate.NewLimiter(2, 4) 1279 1280 af, wf := rate2.NewRate(limiter) 1281 1282 // af.Allow() bool: take 1 token by default 1283 // af.Allow() == af.AllowN(time.Now(), 1) 1284 af.Allow() 1285 1286 // af.AllowN(ctx,n) bool: can take N tokens 1287 af.AllowN(time.Now(), 5) 1288 1289 // wf.Wait(ctx) err: wait for ctx to time out, default takes 1 token 1290 // wf.Wait(ctx) == wf.WaitN(ctx, 1) 1291 _ = wf.Wait(context.TODO()) 1292 1293 // wf.WaitN(ctx, n) err: wait for ctx to time out, can take N tokens 1294 _ = wf.WaitN(context.TODO(), 5) 1295 } 1296 ``` 1297 1298 ### ratelimite 1299 1300 Token bucket 1301 1302 ```go 1303 package main 1304 1305 import ( 1306 "context" 1307 "github.com/juju/ratelimit" 1308 ratelimit2 "github.com/songzhibin97/gkit/restrictor/ratelimite" 1309 "time" 1310 ) 1311 1312 func main() { 1313 // ratelimit:github.com/juju/ratelimit 1314 bucket := ratelimit.NewBucket(time.Second/2, 4) 1315 1316 af, wf := ratelimit2.NewRateLimit(bucket) 1317 // af.Allow() bool: takes 1 token by default 1318 // af.Allow() == af.AllowN(time.Now(), 1) 1319 af.Allow() 1320 1321 // af.AllowN(ctx,n) bool: can take N tokens 1322 af.AllowN(time.Now(), 5) 1323 1324 // wf.Wait(ctx) err: wait for ctx to time out, default takes 1 token 1325 // wf.Wait(ctx) == wf.WaitN(ctx, 1) 1326 _ = wf.Wait(context.TODO()) 1327 1328 // wf.WaitN(ctx, n) err: wait for ctx to time out, can take N tokens 1329 _ = wf.WaitN(context.TODO(), 5) 1330 } 1331 ``` 1332 1333 ## structure (common data structures) 1334 1335 ### hashset 1336 1337 ```go 1338 package main 1339 1340 func main() { 1341 l := hashset.NewInt() 1342 1343 for _, v := range []int{10, 12, 15} { 1344 l.Add(v) 1345 } 1346 1347 if l.Contains(10) { 1348 fmt.Println("hashset contains 10") 1349 } 1350 1351 l.Range(func(value int) bool { 1352 fmt.Println("hashset range found ", value) 1353 return true 1354 }) 1355 1356 l.Remove(15) 1357 fmt.Printf("hashset contains %d items\r\n", l.Len()) 1358 } 1359 ``` 1360 1361 1362 ### lscq 1363 1364 ```go 1365 package main 1366 1367 func main() { 1368 l := lscq.NewUint64() 1369 1370 ok := l.Enqueue(1) 1371 if !ok { 1372 panic("enqueue failed") 1373 } 1374 v, err := l.Dequeue() 1375 if err != nil { 1376 panic("dequeue failed") 1377 } 1378 fmt.Println("lscq dequeue value:", v) 1379 } 1380 ``` 1381 1382 1383 ### skipmap 1384 1385 ```go 1386 package main 1387 1388 func main() { 1389 m := skipmap.NewInt() 1390 1391 // Correctness. 1392 m.Store(123, "123") 1393 m.Load(123) 1394 m.Delete(123) 1395 m.LoadOrStore(123) 1396 m.LoadAndDelete(123) 1397 } 1398 ``` 1399 1400 ### skipset 1401 1402 ```go 1403 package main 1404 func Example() { 1405 l := skipset.NewInt() 1406 1407 for _, v := range []int{10, 12, 15} { 1408 if l.Add(v) { 1409 fmt.Println("skipset add", v) 1410 } 1411 } 1412 1413 if l.Contains(10) { 1414 fmt.Println("skipset contains 10") 1415 } 1416 1417 l.Range(func(value int) bool { 1418 fmt.Println("skipset range found ", value) 1419 return true 1420 }) 1421 1422 l.Remove(15) 1423 fmt.Printf("skipset contains %d items\r\n", l.Len()) 1424 } 1425 ``` 1426 1427 1428 ### zset View corresponding readme 1429 1430 ## sys 1431 ### mutex 1432 Lock-related wrappers (implements trylock, reentrant locks, etc., reentrant token locks, can also get lock indicator data) 1433 ```go 1434 package main 1435 1436 func main() { 1437 // Get the lock 1438 lk := mutex.NewMutex() 1439 // Try to get a lock 1440 if lk.TryLock() { 1441 // Get the lock 1442 defer lk.Unlock() 1443 } 1444 // Failed to execute other logic 1445 1446 lk.Count() // get the number of locks waiting 1447 1448 lk.IsLocked() // whether the lock is held 1449 1450 lk.IsWoken() // whether a waiter has been woken up internally 1451 1452 lk.IsStarving() // whether it is in starvation mode 1453 1454 // Reentrant locks 1455 // can be acquired multiple times in the same goroutine 1456 rvlk := mutex.NewRecursiveMutex() 1457 rvlk.Lock() 1458 defer rvlk.Unlock() 1459 1460 // token reentrant lock 1461 // Pass in the same token to enable the reentrant function 1462 tklk := mutex.NewTokenRecursiveMutex() 1463 tklk.Lock(token) 1464 defer tklk.Unlock(token) 1465 } 1466 ``` 1467 1468 1469 ## ternary 1470 1471 > Simple implementation of ternary expressions 1472 > The generic version can be used **[go-baseutils](https://github.com/songzhibin97/go-baseutils/tree/main/base/bternaryexpr)** 1473 > Be careful not to use the null pointer directly for point arithmetic, as it needs to be called first as an entry, the solution can be to close the incoming function 1474 1475 ```go 1476 package main 1477 1478 import "github.com/songzhibin97/gkit/ternary" 1479 1480 func main() { 1481 ternary.ReturnInt(true, 1, 2) // 1 1482 } 1483 ``` 1484 1485 ## timeout 1486 1487 > Timeout control between services (and a structure to handle the time format) 1488 1489 ```go 1490 package main 1491 1492 import ( 1493 "context" 1494 "github.com/songzhibin97/gkit/timeout" 1495 "time" 1496 ) 1497 1498 func main() { 1499 // The timeout.Shrink method provides link-wide timeout control 1500 // Just pass in a ctx of the parent node and the timeout to be set, and he will check for you if the ctx has been set before. 1501 // If the timeout has been set, it will be compared with the timeout you currently set, and the smallest one will be set to ensure that the link timeout is not affected downstream. 1502 // d: represents the remaining timeout period 1503 // nCtx: the new context object 1504 // cancel: returns a cancel() method if the timeout was actually set successfully, or an invalid cancel if it was not, but don't worry, it can still be called normally 1505 d, nCtx, cancel := timeout.Shrink(context.Background(), 5*time.Second) 1506 // d as needed 1507 // Generally determine the downstream timeout for the service, if d is too small you can just drop it 1508 select { 1509 case <-nCtx.Done(): 1510 cancel() 1511 default: 1512 // ... 1513 } 1514 _ = d 1515 } 1516 ``` 1517 Other(currently, gorm also has a related type that is supported.) 1518 > timeout.DbJSON // provides some functionality in db json format 1519 > timeout.DTime // provides some functionality in db 15:04:05 format 1520 > DateStruct // provides some functionality in db 15:04:05 format Embedded in struct mode 1521 > Date // provides some functionality in db 2006-01-02 format 1522 > DateTime // provides some functions in db 2006-01-02 15:04:05 format 1523 > DateTimeStruct // provides some functions in db 2006-01-02 15:04:05 format Embed mode as struct 1524 > timeout.Stamp // provides some functionality in db timestamp format 1525 1526 ```go 1527 package main 1528 1529 import ( 1530 "github.com/songzhibin97/gkit/timeout" 1531 "gorm.io/driver/mysql" 1532 "gorm.io/gorm" 1533 "time" 1534 ) 1535 1536 type GoStruct struct { 1537 DateTime timeout.DateTime 1538 DTime timeout.DTime 1539 Date timeout.Date 1540 } 1541 1542 func main() { 1543 // refer to https://github.com/go-sql-driver/mysql#dsn-data-source-name for details 1544 dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" 1545 db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) 1546 if err != nil { 1547 panic(err) 1548 } 1549 db.AutoMigrate(&GoStruct{}) 1550 db.Create(&GoStruct{ 1551 DateTime: timeout.DateTime(time.Now()). 1552 DTime: timeout.DTime(time.Now()). 1553 Date: timeout.Date(time.Now()). 1554 }) 1555 v := &GoStruct{} 1556 db.Find(v) // successfully found 1557 } 1558 1559 ``` 1560 1561 1562 1563 ## tools 1564 1565 ### bind 1566 ```go 1567 1568 package main 1569 1570 // Provide an all-in-one bind tool for gin 1571 import ( 1572 "github.com/songzhibin97/gkit/tools/bind" 1573 1574 "github.com/gin-gonic/gin" 1575 ) 1576 1577 type Test struct { 1578 Json string `json: "json" form: "json,default=jjjson"` 1579 Query string `json: "query" form: "query"` 1580 } 1581 1582 func main() { 1583 r := gin.Default() 1584 r.POST("test", func(c * gin.Context) { 1585 t := Test{} 1586 // url : 127.0.0.1:8080/test?query=query 1587 // { 1588 // "json": "json". 1589 // "query": "query" 1590 // } 1591 // err := c.ShouldBindWith(&t, bind.CreateBindAll(c.ContentType()), bind.) 1592 // Custom binding object 1593 // err := c.ShouldBindWith(&t, bind.CreateBindAll(c.ContentType(), bind.SetSelectorParse([]bind.Binding{}))) 1594 if err != nil { 1595 c.JSON(200, err) 1596 return 1597 } 1598 c.JSON(200, t) 1599 }) 1600 r.Run(":8080") 1601 } 1602 ``` 1603 1604 ### votodo 1605 ```go 1606 package main 1607 1608 import "github.com/songzhibin97/gkit/tools/vto" 1609 1610 type CP struct { 1611 Z1 int `default: "1"` 1612 Z2 string `default: "z2"` 1613 } 1614 1615 func main() { 1616 c1 := CP{ 1617 Z1: 22, 1618 Z2: "33", 1619 } 1620 c2 := CP{} 1621 c3 := CP{} 1622 _ = vto.VoToDo(&c2,&c1) 1623 // c2 CP{ Z1: 22, Z2: "33"} 1624 // same name same type execution copy 1625 // must be dst, src must pass pointer type 1626 1627 // v1.1.2 New default tag 1628 _ = vto.VoToDo(&c2,&c3) 1629 // c2 CP{ Z1: 1, Z2: "z2"} 1630 // same name same type execution copy 1631 // must dst, src must pass pointer type 1632 1633 } 1634 ``` 1635 1636 ### votodoPlus 1637 1638 Added field &tag & default value 1639 1640 ## window 1641 1642 Provide indicator windows 1643 ```go 1644 package main 1645 1646 import ( 1647 "fmt" 1648 "github.com/songzhibin97/gkit/window" 1649 "time" 1650 ) 1651 func main() { 1652 w := window.NewWindow() 1653 slice := []window.Index{ 1654 {Name: "1", Score: 1}, {Name: "2", Score: 2}. 1655 {Name: "2", Score: 2}, {Name: "3", Score: 3}. 1656 {Name: "2", Score: 2}, {Name: "3", Score: 3}. 1657 {Name: "4", Score: 4}, {Name: "3", Score: 3}. 1658 {Name: "5", Score: 5}, {Name: "2", Score: 2}. 1659 {Name: "6", Score: 6}, {Name: "5", Score: 5}. 1660 } 1661 /* 1662 [{1 1} {2 2}] 1663 [{2 4} {3 3} {1 1}] 1664 [{1 1} {2 6} {3 6}] 1665 [{3 9} {4 4} {1 1} {2 6}] 1666 [{1 1} {2 8} {3 9} {4 4} {5 5}] 1667 [{5 10} {3 9} {2 6} {4 4} {6 6}] 1668 */ 1669 for i := 0; i < len(slice); i += 2 { 1670 w.AddIndex(slice[i].Name, slice[i].Score) 1671 w.AddIndex(slice[i+1].Name, slice[i+1].Score) 1672 time.Sleep(time.Second) 1673 fmt.Println(w.Show()) 1674 } 1675 } 1676 ``` 1677 1678 ## trace 1679 Link tracing 1680 1681 ```go 1682 package main 1683 1684 import ( 1685 "context" 1686 "fmt" 1687 1688 gtrace "github.com/songzhibin97/gkit/trace" 1689 "go.opentelemetry.io/otel/trace" 1690 ) 1691 1692 type _Transport struct { 1693 } 1694 1695 func (tr *_Transport) Get(key string) string { 1696 panic("implement me") 1697 } 1698 1699 func (tr *_Transport) Set(key string, value string) { 1700 panic("implement me") 1701 } 1702 1703 func (tr *_Transport) Keys() []string { 1704 panic("implement me") 1705 } 1706 func main() { 1707 // trace.WithServer() server side using middleware 1708 // trace.WithClient() client using middleware 1709 tracer := gtrace.NewTracer(trace.SpanKindServer) 1710 ctx, span := tracer.Start(context.Background(), "Using gkit", &_Transport{}) 1711 fmt.Println(span) 1712 defer tracer.End(ctx, span, "replay", nil) 1713 } 1714 ``` 1715 1716 ## watching 1717 1718 System monitoring (includes cpu, mum, gc, goroutine, etc. window monitoring, dump pprof after preset fluctuation values)