sumologic-query 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/sumologic/cli/commands/discover_source_metadata_command.rb +4 -1
- data/lib/sumologic/cli/commands/list_collectors_command.rb +6 -1
- data/lib/sumologic/cli/commands/list_sources_command.rb +7 -3
- data/lib/sumologic/cli.rb +23 -13
- data/lib/sumologic/client.rb +15 -9
- data/lib/sumologic/metadata/collector.rb +21 -3
- data/lib/sumologic/metadata/source.rb +44 -4
- data/lib/sumologic/metadata/source_metadata_discovery.rb +17 -2
- data/lib/sumologic/utils/time_parser.rb +12 -12
- data/lib/sumologic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17737642aa1c9244133b4442fd6dccc156cf39b5a35cc05071a4769800ad0501
|
|
4
|
+
data.tar.gz: 29037e867772bbc70e2cda259879e8b6d55e51b70611b7ef5167c79ab2eee00e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 67bd5ba57a5a3ed5739d274a25c29e9ba4c1cd2415976a5bb7cbdfb075276c67b614917a14a312e33fa618c15a665ccb7bf82e34b20602ab800e3c00e65bed8c
|
|
7
|
+
data.tar.gz: 2c3fff993dcf6d5a2d14b5719a3fd23331477dece5a43cad0dc5d42e4ae7065fb94bda7741ead8e9a678839d8b5d063bb237c9c301585008fdba427737e1abd8
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
6
6
|
|
|
7
7
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
8
8
|
and release notes are automatically generated from commit messages.
|
|
9
|
+
## [1.4.2](https://github.com/patrick204nqh/sumologic-query/compare/v1.4.1...v1.4.2) (2026-02-11)
|
|
10
|
+
|
|
11
|
+
### 🎉 New Features
|
|
12
|
+
|
|
13
|
+
- add source discovery guidance to skills
|
|
14
|
+
- add filtering options to list-sources
|
|
15
|
+
- add keyword and limit filters to discover-source-metadata
|
|
16
|
+
- add -q/--query and -l/--limit flags to list-collectors
|
|
17
|
+
|
|
18
|
+
### 🐛 Bug Fixes
|
|
19
|
+
|
|
20
|
+
- support compound relative time expressions like -1h30m
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
9
24
|
## [1.4.1](https://github.com/patrick204nqh/sumologic-query/compare/v1.4.0...v1.4.1) (2026-02-11)
|
|
10
25
|
|
|
11
26
|
### 🎉 New Features
|
|
@@ -40,6 +40,7 @@ module Sumologic
|
|
|
40
40
|
end
|
|
41
41
|
warn "Time Zone: #{@parsed_timezone}"
|
|
42
42
|
warn "Filter: #{options[:filter] || 'none (all sources)'}"
|
|
43
|
+
warn "Keyword: #{options[:keyword]}" if options[:keyword]
|
|
43
44
|
warn '-' * 60
|
|
44
45
|
warn 'Running aggregation query to discover sources...'
|
|
45
46
|
$stderr.puts
|
|
@@ -50,7 +51,9 @@ module Sumologic
|
|
|
50
51
|
from_time: @parsed_from,
|
|
51
52
|
to_time: @parsed_to,
|
|
52
53
|
time_zone: @parsed_timezone,
|
|
53
|
-
filter: options[:filter]
|
|
54
|
+
filter: options[:filter],
|
|
55
|
+
keyword: options[:keyword],
|
|
56
|
+
limit: options[:limit]
|
|
54
57
|
)
|
|
55
58
|
end
|
|
56
59
|
end
|
|
@@ -8,7 +8,12 @@ module Sumologic
|
|
|
8
8
|
# Handles the list-collectors command execution
|
|
9
9
|
class ListCollectorsCommand < BaseCommand
|
|
10
10
|
def execute
|
|
11
|
-
list_resource(label: 'collectors', key: :collectors)
|
|
11
|
+
list_resource(label: 'collectors', key: :collectors) do
|
|
12
|
+
client.list_collectors(
|
|
13
|
+
query: options[:query],
|
|
14
|
+
limit: options[:limit]
|
|
15
|
+
)
|
|
16
|
+
end
|
|
12
17
|
end
|
|
13
18
|
end
|
|
14
19
|
end
|
|
@@ -29,10 +29,14 @@ module Sumologic
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def list_all_sources
|
|
32
|
-
warn 'Fetching
|
|
33
|
-
warn 'This may take a minute...'
|
|
32
|
+
warn 'Fetching sources from collectors...'
|
|
34
33
|
|
|
35
|
-
all_sources = client.list_all_sources
|
|
34
|
+
all_sources = client.list_all_sources(
|
|
35
|
+
collector: options[:collector],
|
|
36
|
+
name: options[:name],
|
|
37
|
+
category: options[:category],
|
|
38
|
+
limit: options[:limit]
|
|
39
|
+
)
|
|
36
40
|
|
|
37
41
|
output_json(
|
|
38
42
|
total_collectors: all_sources.size,
|
data/lib/sumologic/cli.rb
CHANGED
|
@@ -41,7 +41,7 @@ module Sumologic
|
|
|
41
41
|
Time Formats:
|
|
42
42
|
--from and --to support multiple formats:
|
|
43
43
|
• 'now' - current time
|
|
44
|
-
• Relative: '-30s', '-5m', '-2h', '-7d', '-1w', '-1M' (
|
|
44
|
+
• Relative: '-30s', '-5m', '-2h', '-1h30m', '-7d', '-1w', '-1M' (compound supported)
|
|
45
45
|
• Unix timestamp: '1700000000' (seconds since epoch)
|
|
46
46
|
• ISO 8601: '2025-11-13T14:00:00'
|
|
47
47
|
|
|
@@ -89,29 +89,36 @@ module Sumologic
|
|
|
89
89
|
Commands::SearchCommand.new(options, create_client).execute
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
desc 'list-collectors', 'List
|
|
92
|
+
desc 'list-collectors', 'List Sumo Logic collectors with optional filters'
|
|
93
93
|
long_desc <<~DESC
|
|
94
|
-
List
|
|
94
|
+
List collectors in your Sumo Logic account.
|
|
95
|
+
Supports filtering by name/category and limiting results.
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
Examples:
|
|
98
|
+
sumo-query list-collectors -q "my-service" -l 20
|
|
97
99
|
sumo-query list-collectors --output collectors.json
|
|
98
100
|
DESC
|
|
101
|
+
option :query, type: :string, aliases: '-q', desc: 'Filter by name or category (case-insensitive)'
|
|
102
|
+
option :limit, type: :numeric, aliases: '-l', desc: 'Maximum collectors to return'
|
|
99
103
|
def list_collectors
|
|
100
104
|
Commands::ListCollectorsCommand.new(options, create_client).execute
|
|
101
105
|
end
|
|
102
106
|
|
|
103
|
-
desc 'list-sources', 'List sources from collectors'
|
|
107
|
+
desc 'list-sources', 'List sources from collectors with optional filters'
|
|
104
108
|
long_desc <<~DESC
|
|
105
|
-
List
|
|
109
|
+
List sources from all collectors, or from a specific collector.
|
|
110
|
+
Supports filtering by collector name, source name, and category.
|
|
106
111
|
|
|
107
112
|
Examples:
|
|
108
|
-
|
|
109
|
-
sumo-query list-sources
|
|
110
|
-
|
|
111
|
-
# List sources for specific collector
|
|
113
|
+
sumo-query list-sources --collector "my-service" --name "nginx" -l 20
|
|
114
|
+
sumo-query list-sources --category "production"
|
|
112
115
|
sumo-query list-sources --collector-id 12345
|
|
113
116
|
DESC
|
|
114
117
|
option :collector_id, type: :string, desc: 'Collector ID to list sources for'
|
|
118
|
+
option :collector, type: :string, desc: 'Filter by collector name (case-insensitive)'
|
|
119
|
+
option :name, type: :string, aliases: '-n', desc: 'Filter by source name (case-insensitive)'
|
|
120
|
+
option :category, type: :string, desc: 'Filter by source category (case-insensitive)'
|
|
121
|
+
option :limit, type: :numeric, aliases: '-l', desc: 'Maximum total sources to return'
|
|
115
122
|
def list_sources
|
|
116
123
|
Commands::ListSourcesCommand.new(options, create_client).execute
|
|
117
124
|
end
|
|
@@ -131,7 +138,7 @@ module Sumologic
|
|
|
131
138
|
Time Formats:
|
|
132
139
|
--from and --to support multiple formats:
|
|
133
140
|
• 'now' - current time
|
|
134
|
-
• Relative: '-30s', '-5m', '-2h', '-7d', '-1w', '-1M' (
|
|
141
|
+
• Relative: '-30s', '-5m', '-2h', '-1h30m', '-7d', '-1w', '-1M' (compound supported)
|
|
135
142
|
• Unix timestamp: '1700000000' (seconds since epoch)
|
|
136
143
|
• ISO 8601: '2025-11-13T14:00:00'
|
|
137
144
|
|
|
@@ -145,8 +152,9 @@ module Sumologic
|
|
|
145
152
|
# Filter by source category (ECS only)
|
|
146
153
|
sumo-query discover-source-metadata --filter '_sourceCategory=*ecs*'
|
|
147
154
|
|
|
148
|
-
#
|
|
149
|
-
sumo-query discover-source-metadata --
|
|
155
|
+
# Filter results by keyword (matches name or category)
|
|
156
|
+
sumo-query discover-source-metadata --keyword nginx
|
|
157
|
+
sumo-query discover-source-metadata --keyword nginx -l 10
|
|
150
158
|
|
|
151
159
|
# Save to file
|
|
152
160
|
sumo-query discover-source-metadata --output discovered-sources.json
|
|
@@ -158,6 +166,8 @@ module Sumologic
|
|
|
158
166
|
option :time_zone, type: :string, default: 'UTC', aliases: '-z',
|
|
159
167
|
desc: 'Time zone (UTC, EST, AEST, +00:00, America/New_York, Australia/Sydney)'
|
|
160
168
|
option :filter, type: :string, desc: 'Optional filter query (e.g., _sourceCategory=*ecs*)'
|
|
169
|
+
option :keyword, type: :string, aliases: '-k', desc: 'Filter results by keyword (matches name or category)'
|
|
170
|
+
option :limit, type: :numeric, aliases: '-l', desc: 'Maximum number of sources to return'
|
|
161
171
|
def discover_source_metadata
|
|
162
172
|
Commands::DiscoverSourceMetadataCommand.new(options, create_client).execute
|
|
163
173
|
end
|
data/lib/sumologic/client.rb
CHANGED
|
@@ -83,11 +83,13 @@ module Sumologic
|
|
|
83
83
|
)
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
# List
|
|
86
|
+
# List collectors with optional filtering
|
|
87
87
|
#
|
|
88
|
+
# @param query [String, nil] Filter by name or category (case-insensitive)
|
|
89
|
+
# @param limit [Integer, nil] Maximum number of collectors to return
|
|
88
90
|
# @return [Array<Hash>] Array of collector hashes
|
|
89
|
-
def list_collectors
|
|
90
|
-
@collector.list
|
|
91
|
+
def list_collectors(query: nil, limit: nil)
|
|
92
|
+
@collector.list(query: query, limit: limit)
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
# List sources for a specific collector
|
|
@@ -98,11 +100,15 @@ module Sumologic
|
|
|
98
100
|
@source.list(collector_id: collector_id)
|
|
99
101
|
end
|
|
100
102
|
|
|
101
|
-
# List all sources from all collectors
|
|
103
|
+
# List all sources from all collectors with optional filtering
|
|
102
104
|
#
|
|
105
|
+
# @param collector [String, nil] Filter collectors by name
|
|
106
|
+
# @param name [String, nil] Filter sources by name
|
|
107
|
+
# @param category [String, nil] Filter sources by category
|
|
108
|
+
# @param limit [Integer, nil] Maximum total sources to return
|
|
103
109
|
# @return [Array<Hash>] Array of { 'collector' => Hash, 'sources' => Array<Hash> }
|
|
104
|
-
def list_all_sources
|
|
105
|
-
@source.list_all
|
|
110
|
+
def list_all_sources(collector: nil, name: nil, category: nil, limit: nil)
|
|
111
|
+
@source.list_all(collector: collector, name: name, category: category, limit: limit)
|
|
106
112
|
end
|
|
107
113
|
|
|
108
114
|
# Discover source metadata from actual log data
|
|
@@ -111,14 +117,14 @@ module Sumologic
|
|
|
111
117
|
# @param from_time [String] Start time (ISO 8601, unix timestamp, or relative)
|
|
112
118
|
# @param to_time [String] End time
|
|
113
119
|
# @param time_zone [String] Time zone (default: UTC)
|
|
114
|
-
# @param
|
|
120
|
+
# @param options [Hash] Optional filters — :filter, :keyword, :limit
|
|
115
121
|
# @return [Hash] Discovery results with source metadata
|
|
116
|
-
def discover_source_metadata(from_time:, to_time:, time_zone: 'UTC',
|
|
122
|
+
def discover_source_metadata(from_time:, to_time:, time_zone: 'UTC', **options)
|
|
117
123
|
@source_metadata_discovery.discover(
|
|
118
124
|
from_time: from_time,
|
|
119
125
|
to_time: to_time,
|
|
120
126
|
time_zone: time_zone,
|
|
121
|
-
|
|
127
|
+
**options
|
|
122
128
|
)
|
|
123
129
|
end
|
|
124
130
|
|
|
@@ -13,9 +13,12 @@ module Sumologic
|
|
|
13
13
|
@http = http_client
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
# List
|
|
17
|
-
#
|
|
18
|
-
|
|
16
|
+
# List collectors with optional client-side filtering
|
|
17
|
+
#
|
|
18
|
+
# @param query [String, nil] Filter by name or category (case-insensitive substring match)
|
|
19
|
+
# @param limit [Integer, nil] Maximum number of collectors to return
|
|
20
|
+
# @return [Array<Hash>] Array of collector objects
|
|
21
|
+
def list(query: nil, limit: nil)
|
|
19
22
|
data = @http.request(
|
|
20
23
|
method: :get,
|
|
21
24
|
path: '/collectors'
|
|
@@ -23,10 +26,25 @@ module Sumologic
|
|
|
23
26
|
|
|
24
27
|
collectors = data['collectors'] || []
|
|
25
28
|
log_info "Found #{collectors.size} collectors"
|
|
29
|
+
|
|
30
|
+
collectors = filter_by_query(collectors, query) if query
|
|
31
|
+
collectors = collectors.take(limit) if limit
|
|
32
|
+
|
|
26
33
|
collectors
|
|
27
34
|
rescue StandardError => e
|
|
28
35
|
raise Error, "Failed to list collectors: #{e.message}"
|
|
29
36
|
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def filter_by_query(collectors, query)
|
|
41
|
+
pattern = query.downcase
|
|
42
|
+
collectors.select do |c|
|
|
43
|
+
name = (c['name'] || '').downcase
|
|
44
|
+
category = (c['category'] || '').downcase
|
|
45
|
+
name.include?(pattern) || category.include?(pattern)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
30
48
|
end
|
|
31
49
|
end
|
|
32
50
|
end
|
|
@@ -31,19 +31,28 @@ module Sumologic
|
|
|
31
31
|
raise Error, "Failed to list sources for collector #{collector_id}: #{e.message}"
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# List all sources from all collectors
|
|
34
|
+
# List all sources from all collectors with optional filtering
|
|
35
35
|
# Returns array of hashes with collector info and their sources
|
|
36
36
|
# Uses parallel fetching with thread pool for better performance
|
|
37
|
-
|
|
37
|
+
#
|
|
38
|
+
# @param collector [String, nil] Filter collectors by name (case-insensitive substring)
|
|
39
|
+
# @param name [String, nil] Filter sources by name (case-insensitive substring)
|
|
40
|
+
# @param category [String, nil] Filter sources by category (case-insensitive substring)
|
|
41
|
+
# @param limit [Integer, nil] Maximum total sources to return
|
|
42
|
+
def list_all(collector: nil, name: nil, category: nil, limit: nil)
|
|
38
43
|
collectors = @collector_client.list
|
|
39
44
|
active_collectors = collectors.select { |c| c['alive'] }
|
|
45
|
+
active_collectors = filter_collectors(active_collectors, collector) if collector
|
|
40
46
|
|
|
41
47
|
log_info "Fetching sources for #{active_collectors.size} active collectors in parallel..."
|
|
42
48
|
|
|
43
|
-
result = @fetcher.fetch_all(active_collectors) do |
|
|
44
|
-
fetch_collector_sources(
|
|
49
|
+
result = @fetcher.fetch_all(active_collectors) do |c|
|
|
50
|
+
fetch_collector_sources(c)
|
|
45
51
|
end
|
|
46
52
|
|
|
53
|
+
result = filter_sources(result, name: name, category: category)
|
|
54
|
+
result = apply_source_limit(result, limit) if limit
|
|
55
|
+
|
|
47
56
|
log_info "Total: #{result.size} collectors with sources"
|
|
48
57
|
result
|
|
49
58
|
rescue StandardError => e
|
|
@@ -52,6 +61,37 @@ module Sumologic
|
|
|
52
61
|
|
|
53
62
|
private
|
|
54
63
|
|
|
64
|
+
def filter_collectors(collectors, pattern)
|
|
65
|
+
pattern = pattern.downcase
|
|
66
|
+
collectors.select { |c| (c['name'] || '').downcase.include?(pattern) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def filter_sources(result, name:, category:)
|
|
70
|
+
matcher = source_matcher(name&.downcase, category&.downcase)
|
|
71
|
+
result.filter_map do |entry|
|
|
72
|
+
filtered = entry['sources'].select(&matcher)
|
|
73
|
+
{ 'collector' => entry['collector'], 'sources' => filtered } unless filtered.empty?
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def source_matcher(name_pattern, cat_pattern)
|
|
78
|
+
lambda do |s|
|
|
79
|
+
(!name_pattern || (s['name'] || '').downcase.include?(name_pattern)) &&
|
|
80
|
+
(!cat_pattern || (s['category'] || '').downcase.include?(cat_pattern))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def apply_source_limit(result, limit)
|
|
85
|
+
remaining = limit
|
|
86
|
+
result.each_with_object([]) do |entry, acc|
|
|
87
|
+
break acc if remaining <= 0
|
|
88
|
+
|
|
89
|
+
sources = entry['sources'].take(remaining)
|
|
90
|
+
acc << { 'collector' => entry['collector'], 'sources' => sources }
|
|
91
|
+
remaining -= sources.size
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
55
95
|
# Fetch sources for a single collector
|
|
56
96
|
# @return [Hash] collector and sources data
|
|
57
97
|
def fetch_collector_sources(collector)
|
|
@@ -22,8 +22,12 @@ module Sumologic
|
|
|
22
22
|
# @param from_time [String] Start time (ISO 8601, unix timestamp, or relative)
|
|
23
23
|
# @param to_time [String] End time
|
|
24
24
|
# @param time_zone [String] Time zone (default: UTC)
|
|
25
|
-
# @param
|
|
26
|
-
def discover(from_time:, to_time:, time_zone: 'UTC',
|
|
25
|
+
# @param options [Hash] Optional filters — :filter, :keyword, :limit
|
|
26
|
+
def discover(from_time:, to_time:, time_zone: 'UTC', **options)
|
|
27
|
+
filter = options[:filter]
|
|
28
|
+
keyword = options[:keyword]
|
|
29
|
+
limit = options[:limit]
|
|
30
|
+
|
|
27
31
|
query = build_query(filter)
|
|
28
32
|
log_info "Discovering source metadata with query: #{query}"
|
|
29
33
|
log_info "Time range: #{from_time} to #{to_time} (#{time_zone})"
|
|
@@ -39,6 +43,8 @@ module Sumologic
|
|
|
39
43
|
)
|
|
40
44
|
|
|
41
45
|
source_models = parse_aggregation_results(records)
|
|
46
|
+
source_models = filter_by_keyword(source_models, keyword) if keyword
|
|
47
|
+
source_models = source_models.take(limit) if limit
|
|
42
48
|
|
|
43
49
|
{
|
|
44
50
|
'time_range' => {
|
|
@@ -47,6 +53,7 @@ module Sumologic
|
|
|
47
53
|
'time_zone' => time_zone
|
|
48
54
|
},
|
|
49
55
|
'filter' => filter,
|
|
56
|
+
'keyword' => keyword,
|
|
50
57
|
'total_sources' => source_models.size,
|
|
51
58
|
'sources' => source_models.map(&:to_h)
|
|
52
59
|
}
|
|
@@ -56,6 +63,14 @@ module Sumologic
|
|
|
56
63
|
|
|
57
64
|
private
|
|
58
65
|
|
|
66
|
+
def filter_by_keyword(source_models, keyword)
|
|
67
|
+
pattern = keyword.downcase
|
|
68
|
+
source_models.select do |s|
|
|
69
|
+
(s.name || '').downcase.include?(pattern) ||
|
|
70
|
+
(s.category || '').downcase.include?(pattern)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
59
74
|
# Build aggregation query to discover sources
|
|
60
75
|
def build_query(filter)
|
|
61
76
|
base = filter || '*'
|
|
@@ -7,7 +7,7 @@ module Sumologic
|
|
|
7
7
|
# Parses various time formats into ISO 8601 strings for the Sumo Logic API
|
|
8
8
|
# Supports:
|
|
9
9
|
# - 'now' - current time
|
|
10
|
-
# - Relative times: '-30s', '-5m', '-2h', '-7d', '-1w', '-1M'
|
|
10
|
+
# - Relative times: '-30s', '-5m', '-2h', '-7d', '-1w', '-1M', '-1h30m'
|
|
11
11
|
# - Unix timestamps: '1700000000' or 1700000000
|
|
12
12
|
# - ISO 8601: '2025-11-13T14:00:00'
|
|
13
13
|
class TimeParser
|
|
@@ -21,7 +21,9 @@ module Sumologic
|
|
|
21
21
|
'M' => 2_592_000 # months (30 days approximation)
|
|
22
22
|
}.freeze
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# Matches single or compound relative times: -30m, -1h30m, -2d3h15m
|
|
25
|
+
RELATIVE_TIME_REGEX = /^([+-])(\d+[smhdwM])+$/.freeze
|
|
26
|
+
RELATIVE_COMPONENT_REGEX = /(\d+)([smhdwM])/.freeze
|
|
25
27
|
|
|
26
28
|
class ParseError < StandardError; end
|
|
27
29
|
|
|
@@ -32,10 +34,8 @@ module Sumologic
|
|
|
32
34
|
def self.parse(time_str, _timezone: 'UTC')
|
|
33
35
|
return parse_now if time_str.to_s.downcase == 'now'
|
|
34
36
|
|
|
35
|
-
# Try relative time format (e.g., '-30m', '+1h')
|
|
36
|
-
if time_str.is_a?(String) &&
|
|
37
|
-
return parse_relative_time(match)
|
|
38
|
-
end
|
|
37
|
+
# Try relative time format (e.g., '-30m', '+1h', '-1h30m')
|
|
38
|
+
return parse_relative_time(time_str) if time_str.is_a?(String) && time_str.match?(RELATIVE_TIME_REGEX)
|
|
39
39
|
|
|
40
40
|
# Try Unix timestamp (integer or numeric string)
|
|
41
41
|
return parse_unix_timestamp(time_str) if unix_timestamp?(time_str)
|
|
@@ -95,14 +95,14 @@ module Sumologic
|
|
|
95
95
|
format_time(Time.now)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
private_class_method def self.parse_relative_time(
|
|
99
|
-
sign
|
|
100
|
-
|
|
101
|
-
amount = -amount if sign == '-'
|
|
98
|
+
private_class_method def self.parse_relative_time(time_str)
|
|
99
|
+
sign = time_str[0]
|
|
100
|
+
components = time_str.scan(RELATIVE_COMPONENT_REGEX)
|
|
102
101
|
|
|
103
|
-
seconds_delta = amount * UNITS[unit]
|
|
104
|
-
|
|
102
|
+
seconds_delta = components.sum { |amount, unit| amount.to_i * UNITS[unit] }
|
|
103
|
+
seconds_delta = -seconds_delta if sign == '-'
|
|
105
104
|
|
|
105
|
+
target_time = Time.now + seconds_delta
|
|
106
106
|
format_time(target_time)
|
|
107
107
|
end
|
|
108
108
|
|
data/lib/sumologic/version.rb
CHANGED