// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2022 Datadog, Inc.
package timer
import (
"time"
)
// Key is used to key track of each component of a tree timer. It can be used create constants that can be used to identify components in the tree.
type Key string
// Timer is the default interface for all timers. NewTimer will provide you with a Timer.
// Keep in mind that they are NOT thread-safe and once Stop() is called, the Timer cannot be restarted.
type Timer interface {
// Start starts the timer and returns the start time.
// If the timer was already started, it returns the previous start time.
// If the timer was started without specifying a budget, it will inherit the budget from its parent when calling Start().
// if the timer has no parent and no budget was specified, the call creating the timer (either NewTreeTimer or NewTimer) will return an error asking to specify a budget (which can be unlimited).
// Start is NOT thread-safe
Start() time.Time
// Stop ends the timer and returns the time spent on the timer as Spent() would.
// Stop will trigger the computation of sum timers if the timer is part of a tree. See NodeTimer for more information.
// Stop is NOT thread-safe
Stop() time.Duration
// Spent returns the current time spent between Start() and Stop() or between Start() and now if the timer is still running.
// Spent is thread-safe
Spent() time.Duration
// Remaining returns the time remaining before the timer reaches its budget. (budget - Spent())
// It returns 0 if the timer is exhausted. Remaining may never return a value below zero.
// Remaining only makes sense if the timer has a budget. If the timer has no budget, it returns the special value UnlimitedBudget.
// Remaining is thread-safe
Remaining() time.Duration
// Exhausted returns true if the timer spent in the timer is greater than the budget. (Spent() > budget)
// Exhausted may return true only in case the time has a budget. If the timer has n, it returns false.
// Exhausted is thread-safe
Exhausted() bool
// Timed is a convenience function that starts the timer, calls the provided function and stops the timer.
// Timed is panic-safe and will stop the timer even if the function panics.
// Timed is NOT thread-safe
Timed(timedFunc func(timer Timer)) time.Duration
}
// SumTimer is a sub-interface for timers capable of having children and making the sum of their time spent.
// NewTreeTimer will provide you with a timer supporting this interface
type SumTimer interface {
// SumSpent returns the sum of the time spent in each component of the timer.
// SumSpent is thread-safe
SumSpent() time.Duration
// SumRemaining returns the sum of the time remaining in each component of the timer.
// SumRemaining returns UnlimitedBudget if the timer has no budget. (UnlimitedBudget)
// SumRemaining is thread-safe
SumRemaining() time.Duration
// SumExhausted returns true if the sum of the time spent in each component of the timer is greater than the budget.
// SumExhausted returns false if the timer has no budget. (UnlimitedBudget)
// SumExhausted is thread-safe
SumExhausted() bool
}
// NodeTimer is the interface for tree timers. NewTreeTimer will provide you with a NodeTimer.
// NodeTimer can have children (NodeTimer or Timer) and will compute the sum of their spent time each time a children timer calls its Stop() method.
// To add children to a NodeTimer, you have to specify component names when creating the timer with the WithComponent and WithComponents options.
// The component names must be unique and cannot be empty. The component names are used to identify the children timers.
// The returned timer can now create children timers using the NewNode and NewLeaf functions using the names provided when creating the parent timer.
// Multiple timers from the same component can be used in parallel and will be summed together.
// In parallel to that, NodeTimer can have their own wall time timer and budget that will apply to the sum of their children and their own timer.
// The following functions are the same as the Timer interface but works using the sum of the children timers:
// - SumSpent() -> Spent()
// - SumRemaining() -> Remaining()
// - SumExhausted() -> Exhausted()
// Keep in mind that the timer itself (only Start and Stop) is NOT thread-safe and once Stop() is called, the NodeTimer cannot be restarted.
type NodeTimer interface {
Timer
SumTimer
// NewNode creates a new NodeTimer with the given name and options. The given name must match one of the component name of the parent timer.
// A node timer is required to have at least one component. If no component is provided, it will return an error asking you to use NewLeaf instead.
// If no budget is provided, it will inherit the budget from its parent when calling Start().
// NewNode is thread-safe
NewNode(name Key, options ...Option) (NodeTimer, error)
// NewLeaf creates a new Timer with the given name and options. The given name must match one of the component name of the parent timer.
// A leaf timer is forbidden to have components. If a component is provided, it will return an error asking you to use NewNode instead.
// If no budget is provided, it will inherit the budget from its parent when calling Start().
// NewLeaf is thread-safe
NewLeaf(name Key, options ...Option) (Timer, error)
// MustLeaf creates a new Timer with the given name and options. The given name must match one of the component name of the parent timer.
// MustLeaf wraps a call to NewLeaf but will panic if the error is not nil.
// MustLeaf is thread-safe
MustLeaf(name Key, options ...Option) Timer
// AddTime adds the given duration to the component of the timer with the given name.
// AddTime is thread-safe
AddTime(name Key, duration time.Duration)
// Stats returns a map of the time spent in each component of the timer.
// Stats is thread-safe
Stats() map[Key]time.Duration
// childStarted is used to propagate the start of a child timer to the parent timer through the whole tree.
childStarted()
// childStopped is used to propagate the time spent in a child timer to the parent timer through the whole tree.
childStopped(componentName Key, duration time.Duration)
// now is a convenience wrapper to swap the time.Now() function for testing and performance purposes.
now() time.Time
}