func MayReplaceLocalhost(host string) string {
	if os.Getenv("IS_DOCKER") != "" {
		return strings.Replace(host, "localhost", "host.docker.internal", 1)
	}
	return host
}
MayReplaceLocalhost when run in docker compose, change localhost to host.docker.internal for accessing host network
package dtmcli
import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/go-resty/resty/v2"
)
func P2E(perr *error) {
	if x := recover(); x != nil {
		if e, ok := x.(error); ok {
			*perr = e
		} else {
			panic(x)
		}
	}
}
func E2P(err error) {
	if err != nil {
		panic(err)
	}
}
func CatchP(f func()) (rerr error) {
	defer P2E(&rerr)
	f()
	return nil
}
func PanicIf(cond bool, err error) {
	if cond {
		panic(err)
	}
}
func MustAtoi(s string) int {
	r, err := strconv.Atoi(s)
	if err != nil {
		E2P(errors.New("convert to int error: " + s))
	}
	return r
}
func OrString(ss ...string) string {
	for _, s := range ss {
		if s != "" {
			return s
		}
	}
	return ""
}
func If(condition bool, trueObj interface{}, falseObj interface{}) interface{} {
	if condition {
		return trueObj
	}
	return falseObj
}
func MustMarshal(v interface{}) []byte {
	b, err := json.Marshal(v)
	E2P(err)
	return b
}
func MustMarshalString(v interface{}) string {
	return string(MustMarshal(v))
}
func MustUnmarshal(b []byte, obj interface{}) {
	err := json.Unmarshal(b, obj)
	E2P(err)
}
func MustUnmarshalString(s string, obj interface{}) {
	MustUnmarshal([]byte(s), obj)
}
func MustRemarshal(from interface{}, to interface{}) {
	b, err := json.Marshal(from)
	E2P(err)
	err = json.Unmarshal(b, to)
	E2P(err)
}
var layout = "2006-01-02 15:04:05.999"
func Logf(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	ts := time.Now().Format(layout)
	var file string
	var line int
	for i := 1; i < 10; i++ {
		_, file, line, _ = runtime.Caller(i)
		if strings.Contains(file, "dtm") {
			break
		}
	}
	fmt.Printf("%s %s:%d %s\n", ts, path.Base(file), line, msg)
}
func LogRedf(fmt string, args ...interface{}) {
	Logf("\x1b[31m\n"+fmt+"\x1b[0m\n", args...)
}
var FatalExitFunc = func() { os.Exit(1) }
func LogFatalf(fmt string, args ...interface{}) {
	fmt += "\n" + string(debug.Stack())
	Logf("\x1b[31m\n"+fmt+"\x1b[0m\n", args...)
	FatalExitFunc()
}
func LogIfFatalf(condition bool, fmt string, args ...interface{}) {
	if condition {
		LogFatalf(fmt, args...)
	}
}
func FatalIfError(err error) {
	LogIfFatalf(err != nil, "Fatal error: %v", err)
}
var RestyClient = resty.New()
func init() {
	RestyClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
		r.URL = MayReplaceLocalhost(r.URL)
		Logf("requesting: %s %s %v %v", r.Method, r.URL, r.Body, r.QueryParam)
		return nil
	})
	RestyClient.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
		r := resp.Request
		Logf("requested: %s %s %s", r.Method, r.URL, resp.String())
		return nil
	})
}
func GetFuncName() string {
	pc, _, _, _ := runtime.Caller(1)
	return runtime.FuncForPC(pc).Name()
}