common/common.go (172 lines of code) (raw):

package utils import ( "encoding/json" "fmt" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "os" "strings" "github.com/nightlyone/lockfile" LOG "github.com/vinllen/log4go" ) // Build info var BRANCH = "$" var SIGNALPROFILE = "$" var SIGNALSTACK = "$" const ( // APPNAME = "mongoshake" // AppDatabase = APPNAME // APPConflictDatabase = APPNAME + "_conflict" GlobalDiagnosticPath = "diagnostic" // This is the time of golang was born to the world GolangSecurityTime = "2006-01-02T15:04:05Z" WorkGood uint64 = 0 GetReady uint64 = 1 FetchBad uint64 = 2 TunnelSendBad uint64 = 4 TunnelSyncBad uint64 = 8 ReplicaExecBad uint64 = 16 MajorityWriteConcern = "majority" Int32max = (int64(1) << 32) - 1 ) var ( AppDatabase = VarCheckpointStorageDbReplicaDefault APPConflictDatabase = VarCheckpointStorageDbReplicaDefault + "_conflict" ) func init() { // prepare global folders Mkdirs(GlobalDiagnosticPath /*, GlobalStoragePath*/) } func RunStatusMessage(status uint64) string { switch status { case WorkGood: return "Good" case GetReady: return "prepare for ready" case FetchBad: return "can't fetch oplog from source MongoDB" case TunnelSendBad: return "collector send oplog to tunnel failed" case TunnelSyncBad: return "receiver fetch from tunnel failed" case ReplicaExecBad: return "receiver replica executed failed" default: return "unknown" } } // InitialLogger initialize logger // // verbose: where log goes to: 0 - file,1 - file+stdout,2 - stdout func InitialLogger(logDir, logFile, level string, logFlush bool, verbose int) error { logLevel := parseLogLevel(level) if verbose > 0 { writer := LOG.NewConsoleLogWriter() writer.SetFormat("[%D %T] [%L] %M") LOG.AddFilter("console", logLevel, writer) } if verbose == 2 { return nil } if len(logDir) == 0 { logDir = "logs" } // check directory exists if _, err := os.Stat(logDir); err != nil && os.IsNotExist(err) { if err := os.MkdirAll(logDir, os.ModeDir|os.ModePerm); err != nil { return fmt.Errorf("create log.dir[%v] failed[%v]", logDir, err) } } if len(logFile) != 0 { if !logFlush { LOG.LogBufferLength = 32 } else { LOG.LogBufferLength = 0 } fileLogger := LOG.NewFileLogWriter(fmt.Sprintf("%s/%s", logDir, logFile), true) fileLogger.SetRotateDaily(true) // fileLogger.SetFormat("[%D %T] [%L] [%s] %M") // print function fileLogger.SetFormat("[%D %T] [%L] %M") fileLogger.SetRotateMaxBackup(7) LOG.AddFilter("file", logLevel, fileLogger) } else { return fmt.Errorf("log.file[%v] shouldn't be empty", logFile) } return nil } func parseLogLevel(level string) LOG.Level { switch strings.ToLower(level) { case "debug": return LOG.DEBUG case "info": return LOG.INFO case "warning": return LOG.WARNING case "error": return LOG.ERROR default: return LOG.DEBUG } } func WritePid(id string) (err error) { var lock lockfile.Lockfile lock, err = lockfile.New(id) if err != nil { return err } if err = lock.TryLock(); err != nil { return err } return nil } func DelayFor(ms int64) { YieldInMs(ms) } /** * block password in mongo_urls: * two kind mongo_urls: * 1. mongodb://username:password@address * 2. username:password@address */ func BlockMongoUrlPassword(url, replace string) string { colon := strings.Index(url, ":") if colon == -1 || colon == len(url)-1 { return url } else if url[colon+1] == '/' { // find the second '/' for colon++; colon < len(url); colon++ { if url[colon] == ':' { break } } if colon == len(url) { return url } } at := strings.Index(url, "@") if at == -1 || at == len(url)-1 || at <= colon { return url } newUrl := make([]byte, 0, len(url)) for i := 0; i < len(url); i++ { if i <= colon || i > at { newUrl = append(newUrl, byte(url[i])) } else if i == at { newUrl = append(newUrl, []byte(replace)...) newUrl = append(newUrl, byte(url[i])) } } return string(newUrl) } // marshal given struct by json func MarshalStruct(input interface{}) string { ret, err := json.Marshal(input) if err != nil { return fmt.Sprintf("marshal struct failed[%v]", err) } return string(ret) } func DuplicateKey(err error) bool { return mongo.IsDuplicateKeyError(err) } // Return true only Indexe only have key _id func HaveIdIndexKey(obj bson.D) bool { for _, ele := range obj { if ele.Key != "key" { continue } keyValue, ok := ele.Value.(bson.D) if !ok { continue } if len(keyValue) > 1 { continue } for _, fieldEle := range keyValue { if fieldEle.Key == "_id" { return true } } } return false }