github.com/waldiirawan/apm-agent-go/v2@v2.2.2/internal/configutil/duration.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package configutil 19 20 import ( 21 "fmt" 22 "strconv" 23 "strings" 24 "time" 25 "unicode" 26 ) 27 28 var durationUnitMap = map[string]time.Duration{ 29 "us": time.Microsecond, 30 "ms": time.Millisecond, 31 "s": time.Second, 32 "m": time.Minute, 33 } 34 35 var allSuffixes = []string{"us", "ms", "s", "m"} 36 37 // DurationOptions can be used to specify the minimum accepted duration unit 38 // for ParseDurationOptions. 39 type DurationOptions struct { 40 MinimumDurationUnit time.Duration 41 } 42 43 // ParseDuration parses s as a duration, accepting a subset 44 // of the syntax supported by time.ParseDuration. 45 // 46 // Valid time units are "ms", "s", "m". 47 func ParseDuration(s string) (time.Duration, error) { 48 return ParseDurationOptions(s, DurationOptions{ 49 MinimumDurationUnit: time.Millisecond, 50 }) 51 } 52 53 // ParseDurationOptions parses s as a duration, accepting a subset of the 54 // syntax supported by time.ParseDuration. It allows a DurationOptions to 55 // be passed to specify the minimum time.Duration unit allowed. 56 // 57 // Valid time units are "us", "ms", "s", "m". 58 func ParseDurationOptions(s string, opts DurationOptions) (time.Duration, error) { 59 orig := s 60 mul := time.Nanosecond 61 if strings.HasPrefix(s, "-") { 62 mul = -1 63 s = s[1:] 64 } 65 66 sep := -1 67 for i, c := range s { 68 if sep == -1 { 69 if c < '0' || c > '9' { 70 sep = i 71 break 72 } 73 } 74 } 75 76 allowedUnitsString := computeAllowedUnitsString(opts.MinimumDurationUnit) 77 if sep == -1 { 78 return 0, fmt.Errorf("missing unit in duration %s (allowed units: %s)", 79 orig, allowedUnitsString, 80 ) 81 } 82 83 n, err := strconv.ParseInt(s[:sep], 10, 32) 84 if err != nil { 85 return 0, fmt.Errorf("invalid duration %s", orig) 86 } 87 88 mul, ok := durationUnitMap[s[sep:]] 89 if ok { 90 if mul < opts.MinimumDurationUnit { 91 return 0, fmt.Errorf("invalid unit in duration %s (allowed units: %s)", 92 orig, allowedUnitsString, 93 ) 94 } 95 return mul * time.Duration(n), nil 96 } 97 98 for _, c := range s[sep:] { 99 if unicode.IsSpace(c) { 100 return 0, fmt.Errorf("invalid character %q in duration %s", c, orig) 101 } 102 } 103 return 0, fmt.Errorf("invalid unit in duration %s (allowed units: %s)", 104 orig, allowedUnitsString, 105 ) 106 } 107 108 func computeAllowedUnitsString(minUnit time.Duration) string { 109 for i, d := range allSuffixes { 110 if minUnit == durationUnitMap[d] { 111 return strings.Join(allSuffixes[i:], ", ") 112 } 113 } 114 return strings.Join(allSuffixes, ", ") 115 }