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  }