Best Testkube code snippet using output.PrintLog
mkv.go
Source:mkv.go
1package mkvlib2import (3 "bytes"4 "encoding/json"5 "fmt"6 "os"7 "path"8 "regexp"9 "strings"10 "time"11)12const (13 mkvmerge = `mkvmerge`14 mkvextract = `mkvextract`15 ass2bdnxml = `ass2bdnxml`16 ffmpeg = `ffmpeg`17)18type mkvInfo struct {19 Attachments []struct {20 ID int `json:"id"`21 FileName string `json:"file_name"`22 Size int `json:"size"`23 ContentType string `json:"content_type"`24 } `json:"attachments"`25 Tracks []struct {26 ID int `json:"id"`27 Type string `json:"type"`28 Codec string `json:"codec"`29 Properties struct {30 Language string `json:"language"`31 TrackName string `json:"track_name"`32 } `json:"properties"`33 }34}35type mkvProcessor struct {36 a2p bool37 apc bool38 mks bool39 pr string40 pf string41 caches []string42 ass2bdnxml bool43 ffmpeg bool44 nrename bool45 check bool46 strict bool47 noverwrite bool48}49func (self *mkvProcessor) GetMKVInfo(file string) *mkvInfo {50 buf := bytes.NewBufferString("")51 if p, err := newProcess(nil, buf, nil, "", mkvmerge, "-J", file); err == nil {52 if s, err := p.Wait(); err == nil && s.ExitCode() == 0 {53 obj := new(mkvInfo)54 _ = json.Unmarshal(buf.Bytes(), obj)55 return obj56 }57 }58 return nil59}60func (self *mkvProcessor) DumpMKV(file, output string, subset bool, lcb logCallback) bool {61 ec := 062 obj := self.GetMKVInfo(file)63 if obj == nil {64 printLog(lcb, logError, `Failed to get the file info: "%s".`, file)65 return false66 }67 attachments := make([]string, 0)68 tracks := make([]string, 0)69 for _, _item := range obj.Attachments {70 attachments = append(attachments, fmt.Sprintf(`%d:%s`, _item.ID, path.Join(output, "fonts", _item.FileName)))71 }72 for _, _item := range obj.Tracks {73 if _item.Type == "subtitles" {74 s := fmt.Sprintf(`%d_%s_%s`, _item.ID, _item.Properties.Language, _item.Properties.TrackName)75 if _item.Codec == "SubStationAlpha" {76 s += ".ass"77 } else {78 s += ".sub"79 }80 tracks = append(tracks, fmt.Sprintf(`%d:%s`, _item.ID, path.Join(output, s)))81 }82 }83 la := len(attachments)84 lt := len(tracks)85 if la > 0 || lt > 0 {86 args := make([]string, 0)87 args = append(args, file)88 if la > 0 {89 args = append(args, "attachments")90 args = append(args, attachments...)91 }92 if lt > 0 {93 args = append(args, "tracks")94 args = append(args, tracks...)95 }96 if p, err := newProcess(nil, nil, nil, "", mkvextract, args...); err == nil {97 s, err := p.Wait()98 ok := err == nil && s.ExitCode() == 099 if ok {100 if subset {101 asses := make([]string, 0)102 for _, _item := range tracks {103 f := _item[strings.Index(_item, ":")+1:]104 if strings.HasSuffix(f, ".ass") {105 asses = append(asses, f)106 }107 if len(asses) > 0 {108 if !self.ASSFontSubset(asses, "", "", false, lcb) {109 ec++110 }111 }112 }113 }114 } else {115 ec++116 }117 } else {118 ec++119 }120 } else {121 printLog(lcb, logInfo, `This file is not has the subtitles & attachments: "%s"`, file)122 }123 return ec == 0124}125func (self *mkvProcessor) CheckSubset(file string, lcb logCallback) (bool, bool) {126 obj := self.GetMKVInfo(file)127 if obj == nil {128 printLog(lcb, logError, `Failed to get the file info: "%s".`, file)129 return false, true130 }131 ass := false132 ok := false133 reg, _ := regexp.Compile(`\.[A-Z0-9]{8}\.\S+$`)134 for _, track := range obj.Tracks {135 ass = track.Type == "subtitles" && track.Codec == "SubStationAlpha"136 if ass {137 break138 }139 }140 for _, attachment := range obj.Attachments {141 ok = !ass || (strings.HasPrefix(attachment.ContentType, "font/") && reg.MatchString(attachment.FileName))142 if ok {143 break144 }145 }146 return !ass || (ass && ok), false147}148func (self *mkvProcessor) CreateMKV(file string, tracks, attachments []string, output, slang, stitle string, clean bool) bool {149 args := make([]string, 0)150 if clean && !self.mks {151 args = append(args, "--no-subtitles", "--no-attachments")152 }153 d, _, _, ne := splitPath(output)154 if !self.mks {155 args = append(args, file)156 output = path.Join(d, ne+".mkv")157 } else {158 output = path.Join(d, ne+".mks")159 }160 args = append(args, "--output", output)161 for _, _item := range attachments {162 args = append(args, "--attach-file", _item)163 }164 for _, _item := range tracks {165 _, _, _, f := splitPath(_item)166 _arr := strings.Split(f, "_")167 _sl := slang168 _st := stitle169 if len(_arr) > 1 {170 _sl = _arr[1]171 }172 if len(_arr) > 2 {173 _st = _arr[2]174 }175 if _sl != "" {176 args = append(args, "--language", "0:"+_sl)177 }178 if _st != "" {179 args = append(args, "--track-name", "0:"+_st)180 }181 args = append(args, _item)182 }183 if p, err := newProcess(nil, nil, nil, "", mkvmerge, args...); err == nil {184 s, err := p.Wait()185 ok := err == nil && s.ExitCode() != 2186 if !ok {187 _ = os.Remove(output)188 }189 return ok190 }191 return false192}193func (self *mkvProcessor) DumpMKVs(dir, output string, subset bool, lcb logCallback) bool {194 ok := true195 files := findMKVs(dir)196 l := len(files)197 _ok := 0198 for _, item := range files {199 p := strings.TrimPrefix(item, dir)200 d, _, _, f := splitPath(p)201 p = path.Join(output, d, f)202 if !self.DumpMKV(item, p, subset, lcb) {203 ok = false204 printLog(lcb, logError, `Failed to dump the file: "%s".`, item)205 } else {206 _ok++207 printLog(lcb, logProgress, "Dump (%d/%d) done.", _ok, l)208 }209 }210 return ok211}212func (self *mkvProcessor) QueryFolder(dir string, lcb logCallback) []string {213 lines := make([]string, 0)214 files := findMKVs(dir)215 l := len(files)216 for i, file := range files {217 a, b := self.CheckSubset(file, lcb)218 if b {219 printLog(lcb, logError, `Failed to check subset for file: "%s".`, file)220 } else if !a {221 lines = append(lines, file)222 }223 printLog(lcb, logProgress, "Query (%d/%d) done.", i+1, l)224 }225 return lines226}227func (self *mkvProcessor) CreateMKVs(vDir, sDir, fDir, tDir, oDir, slang, stitle string, clean bool, lcb logCallback) bool {228 ok := true229 if tDir == "" {230 tDir = os.TempDir()231 }232 tDir = path.Join(tDir, randomStr(8))233 files, _ := findPath(vDir, `\.\S+$`)234 l := len(files)235 _ok := 0236 for _, item := range files {237 ec := 0238 _, _, _, _f := splitPath(item)239 tmp, _ := findPath(sDir, fmt.Sprintf(`%s(_[\S ]*)?\.\S+$`, regexp.QuoteMeta(_f)))240 asses := make([]string, 0)241 subs := make([]string, 0)242 p := path.Join(tDir, _f)243 fn := path.Join(oDir, _f)244 if self.mks {245 fn += ".mks"246 } else {247 fn += ".mkv"248 }249 if _a, _ := isExists(fn); _a && self.noverwrite {250 printLog(lcb, logInfo, `Existing file: "%s",skip.`, fn)251 _ok++252 printLog(lcb, logProgress, "Create (%d/%d) done.", _ok, l)253 continue254 }255 for _, sub := range tmp {256 if strings.HasSuffix(sub, ".ass") {257 _, _, _, __f := splitPath(sub)258 _s := path.Join(p, __f) + ".ass"259 _ = copyFileOrDir(sub, _s)260 asses = append(asses, _s)261 } else {262 subs = append(subs, sub)263 }264 }265 attachments := make([]string, 0)266 tracks := make([]string, 0)267 if len(asses) > 0 {268 if !self.ASSFontSubset(asses, fDir, "", false, lcb) {269 ec++270 } else {271 _tracks, _ := findPath(p, `\.pgs$`)272 __p := path.Join(p, "subsetted")273 attachments = findFonts(__p)274 tracks, _ = findPath(__p, `\.ass$`)275 tracks = append(tracks, _tracks...)276 }277 }278 tracks = append(tracks, subs...)279 if ec == 0 && !self.CreateMKV(item, tracks, attachments, fn, slang, stitle, clean) {280 ec++281 }282 if ec > 0 {283 ok = false284 printLog(lcb, logError, `Failed to create the file: "%s".`, item)285 } else {286 _ok++287 printLog(lcb, logProgress, "Create (%d/%d) done.", _ok, l)288 }289 }290 _ = os.RemoveAll(tDir)291 return ok292}293func (self *mkvProcessor) MakeMKVs(dir, data, output, slang, stitle string, lcb logCallback) bool {294 ok := true295 files, _ := findPath(dir, `\.\S+$`)296 l := len(files)297 _ok := 0298 for _, item := range files {299 p := strings.TrimPrefix(item, dir)300 d, _, _, f := splitPath(p)301 fn := path.Join(output, d, f)302 if self.mks {303 fn += ".mks"304 } else {305 fn += ".mkv"306 }307 if _a, _ := isExists(fn); _a && self.noverwrite {308 printLog(lcb, logInfo, `Existing file: "%s",skip.`, fn)309 _ok++310 printLog(lcb, logProgress, "Make (%d/%d) done.", _ok, l)311 continue312 }313 p = path.Join(data, d, f)314 _p := path.Join(p, "subsetted")315 subs, _ := findPath(p, `\.(sub)|(pgs)`)316 asses, _ := findPath(_p, `\.ass$`)317 attachments := findFonts(_p)318 tracks := append(subs, asses...)319 if !self.CreateMKV(item, tracks, attachments, fn, slang, stitle, true) {320 ok = false321 printLog(lcb, logError, `Failed to make the file: "%s".`, item)322 } else {323 _ok++324 printLog(lcb, logProgress, "Make (%d/%d) done.", _ok, l)325 }326 }327 return ok328}329func (self *mkvProcessor) ASSFontSubset(files []string, fonts, output string, dirSafe bool, lcb logCallback) bool {330 if len(files) == 0 {331 return false332 }333 obj := new(assProcessor)334 obj.files = files335 obj._fonts = fonts336 obj.output = output337 obj.lcb = lcb338 obj.rename = !self.nrename339 obj.check = self.check340 obj.strict = self.strict341 d, _, _, _ := splitPath(obj.files[0])342 if obj._fonts == "" {343 obj._fonts = path.Join(d, "fonts")344 }345 if obj.output == "" {346 obj.output = d347 dirSafe = true348 }349 if dirSafe {350 obj.output = path.Join(obj.output, "subsetted")351 }352 obj.fonts = findFonts(obj._fonts)353 obj.loadCache(self.caches)354 r := obj.parse() && len(obj.matchFonts()) == 0 && obj.createFontsSubset() && obj.changeFontsName() && obj.replaceFontNameInAss()355 if !r {356 _ = os.RemoveAll(obj.output)357 }358 if r && self.a2p {359 r = self.ass2Pgs(obj._files, self.pr, self.pf, obj.output, d, lcb)360 if r && !self.apc {361 _ = os.RemoveAll(obj.output)362 }363 }364 return r365}366func (self *mkvProcessor) A2P(a2p, apc bool, pr, pf string) {367 self.a2p = self.ass2bdnxml && a2p368 self.apc = apc369 self.pr = pr370 self.pf = pf371}372func (self *mkvProcessor) ass2Pgs(input []string, resolution, frameRate, fontsDir, output string, lcb logCallback) bool {373 return self.a2p && ass2Pgs(input, resolution, frameRate, fontsDir, output, lcb)374}375func (self *mkvProcessor) GetFontsList(files []string, fonts string, lcb logCallback) [][]string {376 if len(files) > 0 {377 obj := new(assProcessor)378 obj.files = files379 obj.lcb = lcb380 d, _, _, _ := splitPath(obj.files[0])381 obj._fonts = fonts382 if obj._fonts == "" {383 obj._fonts = path.Join(d, "fonts")384 }385 obj.check = self.check386 obj.strict = self.strict387 obj.loadCache(self.caches)388 return obj.getFontsList()389 }390 return nil391}392func (self *mkvProcessor) CreateFontsCache(dir, output string, lcb logCallback) []string {393 obj := new(assProcessor)394 obj._fonts = dir395 obj.lcb = lcb396 return obj.createFontsCache(output)397}398func (self *mkvProcessor) CopyFontsFromCache(asses []string, dist string, lcb logCallback) bool {399 obj := new(assProcessor)400 obj.lcb = lcb401 obj.files = asses402 obj.output = dist403 obj.check = self.check404 obj.strict = self.strict405 obj.loadCache(self.caches)406 return obj.copyFontsFromCache()407}408func (self *mkvProcessor) GetFontInfo(p string) *fontCache {409 obj := new(assProcessor)410 return obj.createFontCache(p)411}412func (self *mkvProcessor) Cache(ccs []string) {413 self.caches = ccs414}415func (self *mkvProcessor) MKS(mks bool) {416 self.mks = mks417}418func (self *mkvProcessor) Check(check, strict bool) {419 self.check = check420 self.strict = strict421}422func (self *mkvProcessor) NRename(nrename bool) {423 self.nrename = nrename424}425func (self *mkvProcessor) NOverwrite(n bool) {426 self.noverwrite = n427}428func (self *mkvProcessor) CreateBlankOrBurnVideo(t int64, s, enc, ass, fontdir, output string) bool {429 if !self.ffmpeg {430 return false431 }432 args := make([]string, 0)433 args = append(args, "-y", "-hide_banner", "-loglevel", "quiet")434 if enc == "" {435 enc = "libx264"436 }437 if s == "" {438 args = append(args, "-f", "lavfi")439 args = append(args, "-i", fmt.Sprintf("color=c=0x000000:s=%s:r=%s", self.pr, self.pf))440 } else {441 args = append(args, "-i", s)442 }443 if ass != "" && fontdir != "" {444 t = new(assProcessor).getLength(ass).Milliseconds()445 fontdir = strings.ReplaceAll(fontdir, `\`, `/`)446 fontdir = strings.ReplaceAll(fontdir, `:`, `\\:`)447 fontdir = strings.ReplaceAll(fontdir, `[`, `\[`)448 fontdir = strings.ReplaceAll(fontdir, `]`, `\]`)449 ass = strings.ReplaceAll(ass, `\`, `/`)450 ass = strings.ReplaceAll(ass, `:`, `\\:`)451 ass = strings.ReplaceAll(ass, `[`, `\[`)452 ass = strings.ReplaceAll(ass, `]`, `\]`)453 args = append(args, "-vf", fmt.Sprintf(`subtitles=%s:fontsdir=%s`, ass, fontdir))454 }455 if s == "" {456 if t > 0 {457 args = append(args, "-t", fmt.Sprintf("%dms", t))458 } else {459 return false460 }461 }462 args = append(args, "-pix_fmt", "nv12", "-crf", "18")463 args = append(args, "-vcodec", enc)464 args = append(args, output)465 if p, err := newProcess(nil, nil, nil, "", ffmpeg, args...); err == nil {466 s, err := p.Wait()467 ok := err == nil && s.ExitCode() == 0468 if !ok {469 _ = os.Remove(output)470 }471 return ok472 }473 return false474}475func (self *mkvProcessor) CreateTestVideo(asses []string, s, fontdir, enc string, burn bool, lcb logCallback) bool {476 if s == "-" {477 s = ""478 }479 l := len(asses)480 if l == 0 {481 return false482 }483 if burn {484 ec := 0485 _ok := 0486 for _, v := range asses {487 d, _, _, ne := splitPath(v)488 _output := path.Join(d, fmt.Sprintf("%s-test.mp4", ne))489 ok := self.CreateBlankOrBurnVideo(0, s, enc, v, fontdir, _output)490 if !ok {491 ec++492 printLog(lcb, logError, `Failed to create the test video file: "%s"`, _output)493 _ = os.Remove(_output)494 } else {495 _ok++496 printLog(lcb, logProgress, "CT (%d/%d) done.", _ok, l)497 }498 }499 return ec == 0500 }501 _obj := new(assProcessor)502 var t time.Duration503 for _, v := range asses {504 _t := _obj.getLength(v)505 if _t > t {506 t = _t507 }508 }509 ok := true510 _fonts := findFonts(fontdir)511 if len(_fonts) > 0 {512 d, _, _, _ := splitPath(asses[0])513 n := randomStr(8)514 _t := s == ""515 if _t {516 s = path.Join(d, fmt.Sprintf("%s.mp4", n))517 if !self.CreateBlankOrBurnVideo(t.Milliseconds(), "", enc, "", "", s) {518 ok = false519 printLog(lcb, logError, `Failed to create the temp video file: "%s".`, s)520 }521 }522 if ok {523 output := path.Join(d, fmt.Sprintf("%s.mkv", n))524 if !self.CreateMKV(s, asses, _fonts, output, "", "", true) {525 ok = false526 printLog(lcb, logError, `Failed to create the test video file: "%s".`, output)527 } else {528 printLog(lcb, logProgress, "CT done.")529 }530 }531 if _t {532 _ = os.Remove(s)533 }534 } else {535 ok = false536 }537 return ok538}...
logging.go
Source:logging.go
1package logging2import (3 "encoding/json"4 "fmt"5 "io"6 "os"7 "path/filepath"8 "runtime"9 "strings"10 "time"11 "github.com/fatih/color"12 "github.com/jonboulle/clockwork"13)14// Global logging properties15var Output io.Writer = os.Stdout // Output to use for logging16var Pretty = false // Pretty print logs17var Clock = clockwork.NewRealClock() // Clock for log timestamps18var DateTimeFormat = time.RFC3339 // Date format for timestamps19// colors for pretty printing20var (21 soft = color.New(color.FgBlue)22 bright = color.New(color.FgHiWhite)23 red = color.New(color.FgRed)24)25///////////////////////////////////////////////////////////////////////////////26// PACKAGE-LEVEL LOGGING //////////////////////////////////////////////////////27///////////////////////////////////////////////////////////////////////////////28// DefaultLogger is a package-level logger ready to use29var DefaultLogger = Logger{}30func Tag(key string, val interface{}) *log {31 return DefaultLogger.Tag(key, val)32}33func Err(err error) *log {34 return DefaultLogger.Err(err)35}36// Print logs a message to the output37func Print(a ...interface{}) {38 printLog(DefaultLogger.tags, fmt.Sprint(a...), DefaultLogger.EnableDebug)39}40// Printf logs a message to the output41func Printf(format string, a ...interface{}) {42 printLog(DefaultLogger.tags, fmt.Sprintf(format, a...), DefaultLogger.EnableDebug)43}44// Debug only logs a message to the output if the EnableDebug45// is set to true on the Logger46func Debug(a ...interface{}) {47 if DefaultLogger.EnableDebug {48 printLog(DefaultLogger.tags, fmt.Sprint(a...), DefaultLogger.EnableDebug)49 }50}51// Debugf only logs a message to the output if the EnableDebug52// is set to true on the Logger53func Debugf(format string, a ...interface{}) {54 if DefaultLogger.EnableDebug {55 printLog(DefaultLogger.tags, fmt.Sprintf(format, a...), DefaultLogger.EnableDebug)56 }57}58///////////////////////////////////////////////////////////////////////////////59// LOGGER-LEVEL LOGGING ///////////////////////////////////////////////////////60///////////////////////////////////////////////////////////////////////////////61// Logger is used to log messages. Multiple loggers could be used within a project62// if fine-grained control over debug levels is desired63type Logger struct {64 EnableDebug bool65 tags []tag66}67// Tag associates the given key with the given value in68// the resulting message's tags69func (l *Logger) Tag(key string, val interface{}) *log {70 return &log{71 enableDebug: l.EnableDebug,72 tags: append(l.tags, tag{key, val}),73 }74}75// Err is short for Tag("error", err)76func (l *Logger) Err(err error) *log {77 return &log{78 enableDebug: l.EnableDebug,79 tags: append(l.tags, tag{"error", err}),80 }81}82// Print logs a message to the output83func (l *Logger) Print(a ...interface{}) {84 printLog(l.tags, fmt.Sprint(a...), l.EnableDebug)85}86// Printf logs a message to the output87func (l *Logger) Printf(format string, a ...interface{}) {88 printLog(l.tags, fmt.Sprintf(format, a...), l.EnableDebug)89}90// Debug only logs a message to the output if the EnableDebug91// is set to true on the Logger92func (l *Logger) Debug(a ...interface{}) {93 if l.EnableDebug {94 printLog(l.tags, fmt.Sprint(a...), l.EnableDebug)95 }96}97// Debugf only logs a message to the output if the EnableDebug98// is set to true on the Logger99func (l *Logger) Debugf(format string, a ...interface{}) {100 if l.EnableDebug {101 printLog(l.tags, fmt.Sprintf(format, a...), l.EnableDebug)102 }103}104type log struct {105 enableDebug bool106 tags []tag107}108type tag struct {109 key string110 val interface{}111}112// Logger returns a logger with all the tags defined so far113func (l *log) Logger() *Logger {114 return &Logger{115 EnableDebug: l.enableDebug,116 tags: l.tags,117 }118}119// Tag associates the given key with the given value in120// the resulting message's tags121func (l *log) Tag(key string, val interface{}) *log {122 l.tags = append(l.tags, tag{key, val})123 return l124}125// Err is short for Tag("error", err)126func (l *log) Err(err error) *log {127 l.tags = append(l.tags, tag{"error", err})128 return l129}130// Print logs a message to the output131func (l *log) Print(a ...interface{}) {132 printLog(l.tags, fmt.Sprint(a...), l.enableDebug)133}134// Printf logs a message to the output135func (l *log) Printf(format string, a ...interface{}) {136 printLog(l.tags, fmt.Sprintf(format, a...), l.enableDebug)137}138// Debug only logs a message to the output if the EnableDebug139// is set to true on the Logger140func (l *log) Debug(a ...interface{}) {141 if l.enableDebug {142 printLog(l.tags, fmt.Sprint(a...), l.enableDebug)143 }144}145// Debugf only logs a message to the output if the EnableDebug146// is set to true on the Logger147func (l *log) Debugf(format string, a ...interface{}) {148 if l.enableDebug {149 printLog(l.tags, fmt.Sprintf(format, a...), l.enableDebug)150 }151}152///////////////////////////////////////////////////////////////////////////////153// OUTPUT FORMATTING //////////////////////////////////////////////////////////154///////////////////////////////////////////////////////////////////////////////155func printLog(tags []tag, msg string, debugEnabled bool) {156 if Pretty {157 printLogPretty(tags, msg, debugEnabled)158 } else {159 printLogJSON(tags, msg, debugEnabled)160 }161}162func printLogJSON(tags []tag, msg string, debugEnabled bool) {163 now := Clock.Now().Format(DateTimeFormat)164 // marshal msg to make sure output is valid JSON165 jsonMsg, err := json.Marshal(msg)166 if err != nil {167 jsonMsg = []byte("<?>")168 }169 logComponents := []string{170 fmt.Sprintf(`"time":"%s"`, now),171 fmt.Sprintf(`"message":%s`, jsonMsg),172 }173 if debugEnabled {174 caller := "<?>"175 // skip 3: printLogJSON, printLog, and public caller thereof176 _, fileName, lineNum, ok := runtime.Caller(3)177 if ok {178 caller = fmt.Sprintf("%s:%d", filepath.Base(fileName), lineNum)179 }180 logComponents = append(logComponents, fmt.Sprintf(`"caller":"%s"`, caller))181 }182 for _, t := range tags {183 val := `"<?>"`184 rawVal := t.val185 if errVal, ok := t.val.(error); ok {186 rawVal = errVal.Error()187 }188 jsonVal, err := json.Marshal(rawVal)189 if err == nil {190 val = string(jsonVal)191 }192 logComponents = append(logComponents, fmt.Sprintf(`"%s":%s`, t.key, val))193 }194 fmt.Fprintf(Output, "{%s}\n", strings.Join(logComponents, ","))195}196func printLogPretty(tags []tag, msg string, debugEnabled bool) {197 if msg == "" {198 msg = "_"199 }200 now := Clock.Now().Format(DateTimeFormat)201 logComponents := []string{202 soft.Sprint(now),203 bright.Sprint(msg),204 }205 if debugEnabled {206 caller := "<?>"207 // skip 3: printLogJSON, printLog, and public caller thereof208 _, fileName, lineNum, ok := runtime.Caller(3)209 if ok {210 caller = fmt.Sprintf("%s:%d", filepath.Base(fileName), lineNum)211 }212 logComponents = append(logComponents, soft.Sprintf("(%s)", caller))213 }214 for _, t := range tags {215 var val string216 switch t.val.(type) {217 case error:218 val = red.Sprint(t.val)219 default:220 val = bright.Sprint(t.val)221 }222 key := soft.Sprintf("%s=", t.key)223 logComponents = append(logComponents, key+val)224 }225 fmt.Fprintln(Output, strings.Join(logComponents, " "))226}...
logger.go
Source:logger.go
1// +build !js2package logger3import (4 "encoding/json"5 "fmt"6 "io"7 "os"8 "runtime"9 "time"10 "github.com/fatih/color"11 "github.com/shiena/ansicolor"12)13var output = ansicolor.NewAnsiColorWriter(os.Stdout)14// SetOut set writer fo print logs. Default writer is os.Stdout15func SetOut(out io.Writer) {16 output = ansicolor.NewAnsiColorWriter(out)17}18func makeStack() (ret string) {19 st := make([]uintptr, 50)20 cnt := runtime.Callers(4, st)21 st = st[0:cnt]22 for _, r := range st {23 fnc := runtime.FuncForPC(r)24 file, line := fnc.FileLine(r - 1)25 stackLine := fmt.Sprintf("\t%s:%d\n", file, line)26 stackFunc := fmt.Sprintf("\t\t%s\n", fnc.Name())27 if colored {28 stackLine = color.MagentaString(stackLine)29 stackFunc = color.MagentaString(stackFunc)30 }31 ret += stackLine + stackFunc32 }33 return34}35func printLog(colora color.Attribute, prefix string, printTrace bool, message string, v ...interface{}) {36 var f func(format string, a ...interface{}) string37 if colored {38 f = color.New(colora).SprintfFunc()39 } else {40 f = fmt.Sprintf41 }42 var fileName string43 if fname != FileNameNo {44 _, file, line, ok := runtime.Caller(2)45 if !ok {46 file = "???"47 line = 048 }49 if fname == FileNameShort {50 short := file51 for i := len(file) - 1; i > 0; i-- {52 if file[i] == '/' {53 short = file[i+1:]54 break55 }56 }57 file = short58 }59 fileName = fmt.Sprintf(" %s:%d", file, line)60 }61 var stack string62 if printTrace && btrace {63 stack = makeStack()64 }65 fmt.Fprint(output, f("%s %s %s\n", time.Now().Format(timeFormat), prefix+fileName, fmt.Sprintf(message, v...)), stack)66}67// Info prints info log (green if colored)68func Info(message string, v ...interface{}) {69 printLog(color.FgGreen, InfoPrefix, false, message, v...)70}71// Warning prints warning log (yellow if colored)72func Warning(message string, v ...interface{}) {73 printLog(color.FgYellow, WarnPrefix, true, message, v...)74}75// Error prints error log (red if colored)76func Error(message string, v ...interface{}) {77 printLog(color.FgRed, ErrPrefix, true, message, v...)78}79// Debug prints debug log (blue if colored)80func Debug(message string, v ...interface{}) {81 if pdebug {82 printLog(color.FgBlue, DebugPrefix, false, message, v...)83 }84}85// Fatal prints error log and finish proccess by os.Exit(1)86func Fatal(message string, v ...interface{}) {87 printLog(color.FgRed, ErrPrefix, true, message, v...)88 os.Exit(1)89}90// Panic prints error log and call panic91func Panic(message string, v ...interface{}) {92 DisableBTrace()93 printLog(color.FgRed, ErrPrefix, true, message, v...)94 panic(fmt.Sprintf(message, v...))95}96// PanicRecover recovers panic an print error message97func PanicRecover() {98 if err := recover(); err != nil {99 Error("PANIC: %s", err)100 }101}102// ErrorErr prints err as error log and returns true if err!=nil103func ErrorErr(err error) bool {104 if err != nil {105 printLog(color.FgRed, ErrPrefix, true, "%v", err)106 return true107 }108 return false109}110// WarningErr prints err as warning log and returns true if err!=nil111func WarningErr(err error) bool {112 if err != nil {113 printLog(color.FgYellow, WarnPrefix, true, "%v", err)114 return true115 }116 return false117}118// FatalErr prints err as fatal log119func FatalErr(err error) {120 if err != nil {121 printLog(color.FgRed, ErrPrefix, true, "%v", err)122 os.Exit(1)123 }124}125// JSONDebug prints object in json format126func JSONDebug(a interface{}) {127 buf, err := json.MarshalIndent(a, "", " ")128 if !WarningErr(err) {129 Debug("%s", buf)130 }131}...
PrintLog
Using AI Code Generation
1output.PrintLog("Hello World!")2output.PrintLog("Hello World!")3output.PrintLog("Hello World!")4output.PrintLog("Hello World!")5output.PrintLog("Hello World!")6output.PrintLog("Hello World!")7output.PrintLog("Hello World!")8output.PrintLog("Hello World!")9output.PrintLog("Hello World!")10output.PrintLog("Hello World!")11output.PrintLog("Hello World!")12output.PrintLog("Hello World!")13output.PrintLog("Hello World!")14output.PrintLog("Hello World!")15output.PrintLog("Hello World!")16output.PrintLog("Hello World!")17output.PrintLog("Hello World!")18output.PrintLog("Hello World!")19output.PrintLog("Hello World!")20output.PrintLog("Hello World!")
PrintLog
Using AI Code Generation
1import (2func main() {3 fmt.Println("Hello, playground")4 output.PrintLog("Hello, playground")5}6import (7func main() {8 fmt.Println("Hello, playground")9 output.PrintLog("Hello, playground")10}11import "fmt"12func PrintLog(str string) {13 fmt.Println(str)14}15import "fmt"16func PrintLog(str string) {17 fmt.Println(str)18}
PrintLog
Using AI Code Generation
1import "fmt"2import "github.com/GoLangTutorials/GoLangTutorials/2/2"3func main() {4 output := output.Output{}5 output.PrintLog("Hello World")6}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!