Support for filtering logs by resource
This commit is contained in:
parent
8fd11f26b8
commit
9648444b05
3 changed files with 74 additions and 15 deletions
10
cmd/logs.go
10
cmd/logs.go
|
@ -18,6 +18,7 @@ func newLogsCmd() *cobra.Command {
|
||||||
var stack string
|
var stack string
|
||||||
var follow bool
|
var follow bool
|
||||||
var since string
|
var since string
|
||||||
|
var resource string
|
||||||
|
|
||||||
logsCmd := &cobra.Command{
|
logsCmd := &cobra.Command{
|
||||||
Use: "logs",
|
Use: "logs",
|
||||||
|
@ -29,6 +30,11 @@ func newLogsCmd() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := parseRelativeDuration(since)
|
startTime := parseRelativeDuration(since)
|
||||||
|
var resourceFilter *operations.ResourceFilter
|
||||||
|
if resource != "" {
|
||||||
|
var rf = operations.ResourceFilter(resource)
|
||||||
|
resourceFilter = &rf
|
||||||
|
}
|
||||||
|
|
||||||
// IDEA: This map will grow forever as new log entries are found. We may need to do a more approximate
|
// IDEA: This map will grow forever as new log entries are found. We may need to do a more approximate
|
||||||
// approach here to ensure we don't grow memory unboundedly while following logs.
|
// approach here to ensure we don't grow memory unboundedly while following logs.
|
||||||
|
@ -41,6 +47,7 @@ func newLogsCmd() *cobra.Command {
|
||||||
for {
|
for {
|
||||||
logs, err := backend.GetLogs(stackName, operations.LogQuery{
|
logs, err := backend.GetLogs(stackName, operations.LogQuery{
|
||||||
StartTime: startTime,
|
StartTime: startTime,
|
||||||
|
Resource: resourceFilter,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -72,6 +79,9 @@ func newLogsCmd() *cobra.Command {
|
||||||
logsCmd.PersistentFlags().StringVar(
|
logsCmd.PersistentFlags().StringVar(
|
||||||
&since, "since", "",
|
&since, "since", "",
|
||||||
"Only return logs newer than a relative duration ('5s', '2m', '3h'). Defaults to returning all logs.")
|
"Only return logs newer than a relative duration ('5s', '2m', '3h'). Defaults to returning all logs.")
|
||||||
|
logsCmd.PersistentFlags().StringVarP(
|
||||||
|
&resource, "resource", "r", "",
|
||||||
|
"Only return logs for the requested resource ('name', 'type::name' or full URN). Defaults to returning all logs.")
|
||||||
|
|
||||||
return logsCmd
|
return logsCmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,31 @@ type LogEntry struct {
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceFilter specifies a specific resource or subset of resources. It can be provided in three formats:
|
||||||
|
// - Full URN: "<namespace>::<alloc>::<type>::<name>"
|
||||||
|
// - Type + Name: "<type>::<name>"
|
||||||
|
// - Name: "<name>"
|
||||||
|
type ResourceFilter string
|
||||||
|
|
||||||
|
// Query is a filter on logs, in the format '<name>=<val>,<name>=>val>' where <name> is one of the following:
|
||||||
|
// - `URN`
|
||||||
|
// - `QualifiedName`
|
||||||
|
// - `Name`
|
||||||
|
// - `Type`
|
||||||
|
// - `Message`
|
||||||
|
type Query string
|
||||||
|
|
||||||
// LogQuery represents the parameters to a log query operation.
|
// LogQuery represents the parameters to a log query operation.
|
||||||
// All fields are optional, leaving them off returns all logs.
|
// All fields are optional, leaving them off returns all logs.
|
||||||
type LogQuery struct {
|
type LogQuery struct {
|
||||||
|
// StartTime is an optional time indiciating that only logs from after this time should be produced.
|
||||||
StartTime *time.Time
|
StartTime *time.Time
|
||||||
|
// EndTime is an optional time indiciating that only logs from before this time should be produced.
|
||||||
EndTime *time.Time
|
EndTime *time.Time
|
||||||
|
// Query is a string indicating a filter to apply to the logs - query syntax TBD
|
||||||
Query *string
|
Query *string
|
||||||
|
// Resource is a string indicating that logs should be limited toa resource of resoruces
|
||||||
|
Resource *ResourceFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricName is a handle to a metric supported by a Pulumi Framework resources
|
// MetricName is a handle to a metric supported by a Pulumi Framework resources
|
||||||
|
|
|
@ -87,14 +87,17 @@ var _ Provider = (*resourceOperations)(nil)
|
||||||
|
|
||||||
// GetLogs gets logs for a Resource
|
// GetLogs gets logs for a Resource
|
||||||
func (ops *resourceOperations) GetLogs(query LogQuery) (*[]LogEntry, error) {
|
func (ops *resourceOperations) GetLogs(query LogQuery) (*[]LogEntry, error) {
|
||||||
|
// Only get logs for this resource if it matches the resource filter query
|
||||||
|
if ops.matchesResourceFilter(query.Resource) {
|
||||||
|
// Try to get an operations provider for this resource, it may be `nil`
|
||||||
opsProvider, err := ops.getOperationsProvider()
|
opsProvider, err := ops.getOperationsProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if opsProvider != nil {
|
if opsProvider != nil {
|
||||||
// If this resource has an operations provider - use it and don't recur into children. It is the responsibility
|
// If this resource has an operations provider - use it and don't recur into children. It is the
|
||||||
// of it's GetLogs implementation to aggregate all logs from children, either by passing them through or by
|
// responsibility of it's GetLogs implementation to aggregate all logs from children, either by passing them
|
||||||
// filtering specific content out.
|
// through or by filtering specific content out.
|
||||||
logsResult, err := opsProvider.GetLogs(query)
|
logsResult, err := opsProvider.GetLogs(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logsResult, err
|
return logsResult, err
|
||||||
|
@ -103,13 +106,15 @@ func (ops *resourceOperations) GetLogs(query LogQuery) (*[]LogEntry, error) {
|
||||||
return logsResult, nil
|
return logsResult, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// If this resource did not choose to provide it's own logs, recur into children and collect + aggregate their logs.
|
||||||
var logs []LogEntry
|
var logs []LogEntry
|
||||||
for _, child := range ops.resource.children {
|
for _, child := range ops.resource.children {
|
||||||
childOps := &resourceOperations{
|
childOps := &resourceOperations{
|
||||||
resource: child,
|
resource: child,
|
||||||
config: ops.config,
|
config: ops.config,
|
||||||
}
|
}
|
||||||
// TODO: Parallelize these calls to child GetLogs
|
// IDEA: Parallelize these calls to child GetLogs
|
||||||
childLogs, err := childOps.GetLogs(query)
|
childLogs, err := childOps.GetLogs(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &logs, err
|
return &logs, err
|
||||||
|
@ -146,6 +151,31 @@ func (ops *resourceOperations) GetLogs(query LogQuery) (*[]LogEntry, error) {
|
||||||
return &retLogs, nil
|
return &retLogs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchesResourceFilter determines whether this resource matches the provided resource filter.
|
||||||
|
func (ops *resourceOperations) matchesResourceFilter(filter *ResourceFilter) bool {
|
||||||
|
if filter == nil {
|
||||||
|
// No filter, all resources match it.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ops.resource == nil || ops.resource.state == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
urn := ops.resource.state.URN
|
||||||
|
if resource.URN(*filter) == urn {
|
||||||
|
// The filter matched the full URN
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if string(*filter) == string(urn.Type())+"::"+string(urn.Name()) {
|
||||||
|
// The filter matched the '<type>::<name>' part of the URN
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if tokens.QName(*filter) == urn.Name() {
|
||||||
|
// The filter matched the '<name>' part of the URN
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ListMetrics lists metrics for a Resource
|
// ListMetrics lists metrics for a Resource
|
||||||
func (ops *resourceOperations) ListMetrics() []MetricName {
|
func (ops *resourceOperations) ListMetrics() []MetricName {
|
||||||
return []MetricName{}
|
return []MetricName{}
|
||||||
|
|
Loading…
Reference in a new issue