sumologic-query 1.3.4 → 1.4.0

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +85 -270
  4. data/lib/sumologic/cli/commands/base_command.rb +0 -20
  5. data/lib/sumologic/cli/commands/discover_source_metadata_command.rb +59 -0
  6. data/lib/sumologic/cli/commands/export_content_command.rb +20 -0
  7. data/lib/sumologic/cli/commands/get_content_command.rb +20 -0
  8. data/lib/sumologic/cli/commands/get_dashboard_command.rb +20 -0
  9. data/lib/sumologic/cli/commands/get_lookup_command.rb +20 -0
  10. data/lib/sumologic/cli/commands/get_monitor_command.rb +20 -0
  11. data/lib/sumologic/cli/commands/list_apps_command.rb +22 -0
  12. data/lib/sumologic/cli/commands/list_collectors_command.rb +1 -1
  13. data/lib/sumologic/cli/commands/list_dashboards_command.rb +22 -0
  14. data/lib/sumologic/cli/commands/list_fields_command.rb +27 -0
  15. data/lib/sumologic/cli/commands/list_folders_command.rb +55 -0
  16. data/lib/sumologic/cli/commands/list_health_events_command.rb +22 -0
  17. data/lib/sumologic/cli/commands/list_monitors_command.rb +27 -0
  18. data/lib/sumologic/cli/commands/list_sources_command.rb +2 -9
  19. data/lib/sumologic/cli/commands/search_command.rb +56 -18
  20. data/lib/sumologic/cli.rb +319 -1
  21. data/lib/sumologic/client.rb +225 -8
  22. data/lib/sumologic/configuration.rb +27 -9
  23. data/lib/sumologic/http/client.rb +76 -11
  24. data/lib/sumologic/http/connection_pool.rb +7 -5
  25. data/lib/sumologic/http/response_handler.rb +65 -1
  26. data/lib/sumologic/metadata/app.rb +34 -0
  27. data/lib/sumologic/metadata/collector.rb +5 -6
  28. data/lib/sumologic/metadata/collector_source_fetcher.rb +7 -3
  29. data/lib/sumologic/metadata/content.rb +95 -0
  30. data/lib/sumologic/metadata/dashboard.rb +104 -0
  31. data/lib/sumologic/metadata/field.rb +49 -0
  32. data/lib/sumologic/metadata/folder.rb +89 -0
  33. data/lib/sumologic/metadata/health_event.rb +35 -0
  34. data/lib/sumologic/metadata/loggable.rb +32 -0
  35. data/lib/sumologic/metadata/lookup_table.rb +34 -0
  36. data/lib/sumologic/metadata/models.rb +30 -0
  37. data/lib/sumologic/metadata/monitor.rb +113 -0
  38. data/lib/sumologic/metadata/source.rb +8 -15
  39. data/lib/sumologic/metadata/source_metadata_discovery.rb +155 -0
  40. data/lib/sumologic/search/job.rb +17 -1
  41. data/lib/sumologic/search/message_fetcher.rb +4 -1
  42. data/lib/sumologic/search/record_fetcher.rb +125 -0
  43. data/lib/sumologic/utils/worker.rb +18 -4
  44. data/lib/sumologic/version.rb +1 -1
  45. data/lib/sumologic.rb +26 -0
  46. metadata +26 -2
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the get-monitor command execution
9
+ class GetMonitorCommand < BaseCommand
10
+ def execute
11
+ monitor_id = options[:monitor_id]
12
+ warn "Fetching monitor #{monitor_id}..."
13
+ monitor = client.get_monitor(monitor_id: monitor_id)
14
+
15
+ output_json(monitor)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-apps command execution
9
+ class ListAppsCommand < BaseCommand
10
+ def execute
11
+ warn 'Fetching app catalog...'
12
+ apps = client.list_apps
13
+
14
+ output_json(
15
+ total: apps.size,
16
+ apps: apps
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -13,7 +13,7 @@ module Sumologic
13
13
 
14
14
  output_json(
15
15
  total: collectors.size,
16
- collectors: collectors.map { |c| format_collector(c) }
16
+ collectors: collectors
17
17
  )
18
18
  end
19
19
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-dashboards command execution
9
+ class ListDashboardsCommand < BaseCommand
10
+ def execute
11
+ warn 'Fetching dashboards...'
12
+ dashboards = client.list_dashboards(limit: options[:limit] || 100)
13
+
14
+ output_json(
15
+ total: dashboards.size,
16
+ dashboards: dashboards
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-fields command execution
9
+ class ListFieldsCommand < BaseCommand
10
+ def execute
11
+ if options[:builtin]
12
+ warn 'Fetching built-in fields...'
13
+ fields = client.list_builtin_fields
14
+ else
15
+ warn 'Fetching custom fields...'
16
+ fields = client.list_fields
17
+ end
18
+
19
+ output_json(
20
+ total: fields.size,
21
+ fields: fields
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-folders command execution
9
+ class ListFoldersCommand < BaseCommand
10
+ def execute
11
+ if options[:tree]
12
+ fetch_tree
13
+ elsif options[:folder_id]
14
+ fetch_folder
15
+ else
16
+ fetch_personal
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def fetch_personal
23
+ warn 'Fetching personal folder...'
24
+ folder = client.personal_folder
25
+ output_folder_with_children(folder)
26
+ end
27
+
28
+ def fetch_folder
29
+ folder_id = options[:folder_id]
30
+ warn "Fetching folder #{folder_id}..."
31
+ folder = client.get_folder(folder_id: folder_id)
32
+ output_folder_with_children(folder)
33
+ end
34
+
35
+ def fetch_tree
36
+ folder_id = options[:folder_id]
37
+ max_depth = options[:depth] || 3
38
+
39
+ if folder_id
40
+ warn "Fetching folder tree for #{folder_id} (depth: #{max_depth})..."
41
+ else
42
+ warn "Fetching personal folder tree (depth: #{max_depth})..."
43
+ end
44
+
45
+ tree = client.folder_tree(folder_id: folder_id, max_depth: max_depth)
46
+ output_json(tree)
47
+ end
48
+
49
+ def output_folder_with_children(folder)
50
+ output_json(folder)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-health-events command execution
9
+ class ListHealthEventsCommand < BaseCommand
10
+ def execute
11
+ warn 'Fetching health events...'
12
+ events = client.list_health_events(limit: options[:limit] || 100)
13
+
14
+ output_json(
15
+ total: events.size,
16
+ healthEvents: events
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Sumologic
6
+ class CLI < Thor
7
+ module Commands
8
+ # Handles the list-monitors command execution
9
+ # Uses the monitors search API for flat, filterable results
10
+ class ListMonitorsCommand < BaseCommand
11
+ def execute
12
+ warn 'Fetching monitors...'
13
+ monitors = client.list_monitors(
14
+ query: options[:query],
15
+ status: options[:status],
16
+ limit: options[:limit] || 100
17
+ )
18
+
19
+ output_json(
20
+ total: monitors.size,
21
+ monitors: monitors
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -24,7 +24,7 @@ module Sumologic
24
24
  output_json(
25
25
  collector_id: options[:collector_id],
26
26
  total: sources.size,
27
- sources: sources.map { |s| format_source(s) }
27
+ sources: sources
28
28
  )
29
29
  end
30
30
 
@@ -37,16 +37,9 @@ module Sumologic
37
37
  output_json(
38
38
  total_collectors: all_sources.size,
39
39
  total_sources: all_sources.sum { |c| c['sources'].size },
40
- data: all_sources.map { |item| format_collector_with_sources(item) }
40
+ data: all_sources
41
41
  )
42
42
  end
43
-
44
- def format_collector_with_sources(item)
45
- {
46
- collector: item['collector'],
47
- sources: item['sources'].map { |s| format_source(s) }
48
- }
49
- end
50
43
  end
51
44
  end
52
45
  end
@@ -52,36 +52,74 @@ module Sumologic
52
52
  end
53
53
 
54
54
  def perform_search
55
- client.search(
56
- query: options[:query],
57
- from_time: @parsed_from,
58
- to_time: @parsed_to,
59
- time_zone: @parsed_timezone,
60
- limit: options[:limit]
61
- )
55
+ if aggregate_mode?
56
+ client.search_aggregation(
57
+ query: options[:query],
58
+ from_time: @parsed_from,
59
+ to_time: @parsed_to,
60
+ time_zone: @parsed_timezone,
61
+ limit: options[:limit]
62
+ )
63
+ else
64
+ client.search(
65
+ query: options[:query],
66
+ from_time: @parsed_from,
67
+ to_time: @parsed_to,
68
+ time_zone: @parsed_timezone,
69
+ limit: options[:limit]
70
+ )
71
+ end
72
+ end
73
+
74
+ def aggregate_mode?
75
+ options[:aggregate] || aggregation_query?(options[:query])
76
+ end
77
+
78
+ def aggregation_query?(query)
79
+ query.match?(/\|\s*(count|sum|avg|min|max|pct|first|last|group)\b/i)
62
80
  end
63
81
 
64
82
  def display_results_summary(results)
83
+ result_type = aggregate_mode? ? 'records' : 'messages'
65
84
  warn '=' * 60
66
- warn "Results: #{results.size} messages"
85
+ warn "Results: #{results.size} #{result_type}"
67
86
  warn '=' * 60
68
87
  $stderr.puts
69
88
  end
70
89
 
71
90
  def output_search_results(results)
72
- output_json(
73
- query: options[:query],
74
- from: @parsed_from,
75
- to: @parsed_to,
76
- from_original: @original_from,
77
- to_original: @original_to,
78
- time_zone: @parsed_timezone,
79
- message_count: results.size,
80
- messages: results
81
- )
91
+ if aggregate_mode?
92
+ output_json(
93
+ query: options[:query],
94
+ from: @parsed_from,
95
+ to: @parsed_to,
96
+ from_original: @original_from,
97
+ to_original: @original_to,
98
+ time_zone: @parsed_timezone,
99
+ record_count: results.size,
100
+ records: results
101
+ )
102
+ else
103
+ output_json(
104
+ query: options[:query],
105
+ from: @parsed_from,
106
+ to: @parsed_to,
107
+ from_original: @original_from,
108
+ to_original: @original_to,
109
+ time_zone: @parsed_timezone,
110
+ message_count: results.size,
111
+ messages: results
112
+ )
113
+ end
82
114
  end
83
115
 
84
116
  def launch_interactive_mode(results)
117
+ if aggregate_mode?
118
+ warn 'Interactive mode is not supported for aggregation queries'
119
+ output_search_results(results)
120
+ return
121
+ end
122
+
85
123
  require_relative '../../interactive'
86
124
 
87
125
  formatted_results = build_formatted_results(results)
data/lib/sumologic/cli.rb CHANGED
@@ -5,11 +5,23 @@ require 'json'
5
5
  require_relative 'cli/commands/search_command'
6
6
  require_relative 'cli/commands/list_collectors_command'
7
7
  require_relative 'cli/commands/list_sources_command'
8
+ require_relative 'cli/commands/discover_source_metadata_command'
9
+ require_relative 'cli/commands/list_monitors_command'
10
+ require_relative 'cli/commands/get_monitor_command'
11
+ require_relative 'cli/commands/list_folders_command'
12
+ require_relative 'cli/commands/list_dashboards_command'
13
+ require_relative 'cli/commands/get_dashboard_command'
14
+ require_relative 'cli/commands/list_health_events_command'
15
+ require_relative 'cli/commands/list_fields_command'
16
+ require_relative 'cli/commands/get_lookup_command'
17
+ require_relative 'cli/commands/list_apps_command'
18
+ require_relative 'cli/commands/get_content_command'
19
+ require_relative 'cli/commands/export_content_command'
8
20
 
9
21
  module Sumologic
10
22
  # Thor-based CLI for Sumo Logic query tool
11
23
  # Delegates commands to specialized command classes
12
- class CLI < Thor
24
+ class CLI < Thor # rubocop:disable Metrics/ClassLength
13
25
  class_option :debug, type: :boolean, aliases: '-d', desc: 'Enable debug output'
14
26
  class_option :output, type: :string, aliases: '-o', desc: 'Output file (default: stdout)'
15
27
 
@@ -33,6 +45,10 @@ module Sumologic
33
45
  • Unix timestamp: '1700000000' (seconds since epoch)
34
46
  • ISO 8601: '2025-11-13T14:00:00'
35
47
 
48
+ Aggregation Mode (--aggregate):
49
+ Use --aggregate (-a) for queries with count, sum, avg, group by, etc.
50
+ Returns aggregation records instead of raw log messages.
51
+
36
52
  Examples:
37
53
  # Last 30 minutes
38
54
  sumo-query search --query 'error' --from '-30m' --to 'now'
@@ -52,6 +68,14 @@ module Sumologic
52
68
  # Interactive mode with FZF
53
69
  sumo-query search --query 'error' \\
54
70
  --from '-1h' --to 'now' --interactive
71
+
72
+ # Aggregation query (count by source)
73
+ sumo-query search --query '* | count by _sourceCategory' \\
74
+ --from '-1h' --to 'now' --aggregate
75
+
76
+ # Top errors by count
77
+ sumo-query search --query 'error | count by _sourceHost | top 10' \\
78
+ --from '-24h' --to 'now' --aggregate
55
79
  DESC
56
80
  option :query, type: :string, required: true, aliases: '-q', desc: 'Search query'
57
81
  option :from, type: :string, required: true, aliases: '-f', desc: 'Start time (now, -30m, unix timestamp, ISO 8601)'
@@ -59,6 +83,7 @@ module Sumologic
59
83
  option :time_zone, type: :string, default: 'UTC', aliases: '-z',
60
84
  desc: 'Time zone (UTC, EST, AEST, +00:00, America/New_York, Australia/Sydney)'
61
85
  option :limit, type: :numeric, aliases: '-l', desc: 'Maximum messages to return'
86
+ option :aggregate, type: :boolean, aliases: '-a', desc: 'Return aggregation records (for count/group by queries)'
62
87
  option :interactive, type: :boolean, aliases: '-i', desc: 'Launch interactive browser (requires fzf)'
63
88
  def search
64
89
  Commands::SearchCommand.new(options, create_client).execute
@@ -91,6 +116,299 @@ module Sumologic
91
116
  Commands::ListSourcesCommand.new(options, create_client).execute
92
117
  end
93
118
 
119
+ desc 'discover-source-metadata', 'Discover source metadata from log data using search aggregation'
120
+ long_desc <<~DESC
121
+ Discovers source metadata from actual log data using search aggregation.
122
+ Useful for CloudWatch/ECS/Lambda sources with dynamic _sourceName values
123
+ that are not visible in the Collectors API.
124
+
125
+ Note: This is not an official Sumo Logic API. It runs the search query:
126
+ * | count by _sourceName, _sourceCategory | sort by _count desc
127
+ This is a well-known technique in the Sumo Logic community to discover
128
+ runtime sources, complementing the static source configuration from
129
+ the Collectors API (list-sources).
130
+
131
+ Time Formats:
132
+ --from and --to support multiple formats:
133
+ • 'now' - current time
134
+ • Relative: '-30s', '-5m', '-2h', '-7d', '-1w', '-1M' (sec/min/hour/day/week/month)
135
+ • Unix timestamp: '1700000000' (seconds since epoch)
136
+ • ISO 8601: '2025-11-13T14:00:00'
137
+
138
+ Examples:
139
+ # Discover all sources from last 24 hours (default)
140
+ sumo-query discover-source-metadata
141
+
142
+ # Discover sources from last 7 days
143
+ sumo-query discover-source-metadata --from '-7d' --to 'now'
144
+
145
+ # Filter by source category (ECS only)
146
+ sumo-query discover-source-metadata --filter '_sourceCategory=*ecs*'
147
+
148
+ # Discover CloudWatch sources
149
+ sumo-query discover-source-metadata --filter '_sourceCategory=*cloudwatch*'
150
+
151
+ # Save to file
152
+ sumo-query discover-source-metadata --output discovered-sources.json
153
+ DESC
154
+ option :from, type: :string, default: '-24h', aliases: '-f',
155
+ desc: 'Start time (default: -24h)'
156
+ option :to, type: :string, default: 'now', aliases: '-t',
157
+ desc: 'End time (default: now)'
158
+ option :time_zone, type: :string, default: 'UTC', aliases: '-z',
159
+ desc: 'Time zone (UTC, EST, AEST, +00:00, America/New_York, Australia/Sydney)'
160
+ option :filter, type: :string, desc: 'Optional filter query (e.g., _sourceCategory=*ecs*)'
161
+ def discover_source_metadata
162
+ Commands::DiscoverSourceMetadataCommand.new(options, create_client).execute
163
+ end
164
+
165
+ # ============================================================
166
+ # Monitors Commands
167
+ # ============================================================
168
+
169
+ desc 'list-monitors', 'List monitors with optional status and query filters'
170
+ long_desc <<~DESC
171
+ List monitors in your Sumo Logic account using the search API.
172
+ Supports filtering by monitor status and text query.
173
+
174
+ Status Values:
175
+ Normal, Critical, Warning, MissingData, Disabled, AllTriggered
176
+
177
+ Examples:
178
+ # List all monitors
179
+ sumo-query list-monitors
180
+
181
+ # List only critical monitors
182
+ sumo-query list-monitors --status Critical
183
+
184
+ # List all currently triggered monitors
185
+ sumo-query list-monitors --status AllTriggered
186
+
187
+ # Search monitors by name
188
+ sumo-query list-monitors --query "prod"
189
+
190
+ # Combine status and query filters
191
+ sumo-query list-monitors --status Warning --query "latency"
192
+
193
+ # Save to file
194
+ sumo-query list-monitors --output monitors.json
195
+ DESC
196
+ option :limit, type: :numeric, aliases: '-l', default: 100, desc: 'Maximum monitors to return'
197
+ option :status, type: :string, aliases: '-s',
198
+ desc: 'Filter by status (Normal, Critical, Warning, MissingData, Disabled, AllTriggered)'
199
+ option :query, type: :string, aliases: '-q', desc: 'Search query to filter monitors'
200
+ def list_monitors
201
+ Commands::ListMonitorsCommand.new(options, create_client).execute
202
+ end
203
+
204
+ desc 'get-monitor', 'Get a specific monitor by ID'
205
+ long_desc <<~DESC
206
+ Get detailed information about a specific monitor.
207
+
208
+ Example:
209
+ sumo-query get-monitor --monitor-id 0000000000123456
210
+ DESC
211
+ option :monitor_id, type: :string, required: true, desc: 'Monitor ID'
212
+ # rubocop:disable Naming/AccessorMethodName -- Thor CLI command, not a getter
213
+ def get_monitor
214
+ Commands::GetMonitorCommand.new(options, create_client).execute
215
+ end
216
+ # rubocop:enable Naming/AccessorMethodName
217
+
218
+ # ============================================================
219
+ # Folders Commands (Content Library)
220
+ # ============================================================
221
+
222
+ desc 'list-folders', 'List folders in content library'
223
+ long_desc <<~DESC
224
+ List folders in the Sumo Logic content library.
225
+ By default, shows your personal folder.
226
+
227
+ Examples:
228
+ # List personal folder contents
229
+ sumo-query list-folders
230
+
231
+ # List specific folder
232
+ sumo-query list-folders --folder-id 0000000000123456
233
+
234
+ # Get folder tree (recursive)
235
+ sumo-query list-folders --tree --depth 3
236
+
237
+ # Save to file
238
+ sumo-query list-folders --output folders.json
239
+ DESC
240
+ option :folder_id, type: :string, desc: 'Folder ID to list (default: personal folder)'
241
+ option :tree, type: :boolean, desc: 'Fetch recursive tree structure'
242
+ option :depth, type: :numeric, default: 3, desc: 'Maximum tree depth (default: 3)'
243
+ def list_folders
244
+ Commands::ListFoldersCommand.new(options, create_client).execute
245
+ end
246
+
247
+ # ============================================================
248
+ # Dashboards Commands
249
+ # ============================================================
250
+
251
+ desc 'list-dashboards', 'List all dashboards'
252
+ long_desc <<~DESC
253
+ List all dashboards in your Sumo Logic account.
254
+
255
+ Examples:
256
+ # List all dashboards
257
+ sumo-query list-dashboards
258
+
259
+ # List dashboards with limit
260
+ sumo-query list-dashboards --limit 50
261
+
262
+ # Save to file
263
+ sumo-query list-dashboards --output dashboards.json
264
+ DESC
265
+ option :limit, type: :numeric, aliases: '-l', default: 100, desc: 'Maximum dashboards to return'
266
+ def list_dashboards
267
+ Commands::ListDashboardsCommand.new(options, create_client).execute
268
+ end
269
+
270
+ desc 'get-dashboard', 'Get a specific dashboard by ID'
271
+ long_desc <<~DESC
272
+ Get detailed information about a specific dashboard including panels.
273
+
274
+ Example:
275
+ sumo-query get-dashboard --dashboard-id 0000000000123456
276
+ DESC
277
+ option :dashboard_id, type: :string, required: true, desc: 'Dashboard ID'
278
+ # rubocop:disable Naming/AccessorMethodName -- Thor CLI command, not a getter
279
+ def get_dashboard
280
+ Commands::GetDashboardCommand.new(options, create_client).execute
281
+ end
282
+ # rubocop:enable Naming/AccessorMethodName
283
+
284
+ # ============================================================
285
+ # Health Events Commands
286
+ # ============================================================
287
+
288
+ desc 'list-health-events', 'List health events for collectors, sources, and ingest budgets'
289
+ long_desc <<~DESC
290
+ List health events from your Sumo Logic account.
291
+ Shows collector, source, and ingest budget health status.
292
+
293
+ Examples:
294
+ # List health events
295
+ sumo-query list-health-events
296
+
297
+ # Save to file
298
+ sumo-query list-health-events --output health.json
299
+ DESC
300
+ option :limit, type: :numeric, aliases: '-l', default: 100, desc: 'Maximum events to return'
301
+ def list_health_events
302
+ Commands::ListHealthEventsCommand.new(options, create_client).execute
303
+ end
304
+
305
+ # ============================================================
306
+ # Fields Commands
307
+ # ============================================================
308
+
309
+ desc 'list-fields', 'List custom or built-in log fields'
310
+ long_desc <<~DESC
311
+ List fields available in your Sumo Logic account.
312
+ By default, lists custom fields. Use --builtin for built-in fields.
313
+
314
+ Examples:
315
+ # List custom fields
316
+ sumo-query list-fields
317
+
318
+ # List built-in fields
319
+ sumo-query list-fields --builtin
320
+
321
+ # Save to file
322
+ sumo-query list-fields --output fields.json
323
+ DESC
324
+ option :builtin, type: :boolean, desc: 'List built-in fields instead of custom fields'
325
+ def list_fields
326
+ Commands::ListFieldsCommand.new(options, create_client).execute
327
+ end
328
+
329
+ # ============================================================
330
+ # Lookup Tables Commands
331
+ # ============================================================
332
+
333
+ desc 'get-lookup', 'Get a specific lookup table by ID'
334
+ long_desc <<~DESC
335
+ Get detailed information about a specific lookup table.
336
+ Note: There is no list-all endpoint for lookup tables in the Sumo Logic API.
337
+
338
+ Example:
339
+ sumo-query get-lookup --lookup-id 0000000000123456
340
+ DESC
341
+ option :lookup_id, type: :string, required: true, desc: 'Lookup table ID'
342
+ # rubocop:disable Naming/AccessorMethodName -- Thor CLI command, not a getter
343
+ def get_lookup
344
+ Commands::GetLookupCommand.new(options, create_client).execute
345
+ end
346
+ # rubocop:enable Naming/AccessorMethodName
347
+
348
+ # ============================================================
349
+ # Apps Commands (Catalog)
350
+ # ============================================================
351
+
352
+ desc 'list-apps', 'List available apps from the Sumo Logic catalog'
353
+ long_desc <<~DESC
354
+ List apps available in the Sumo Logic app catalog.
355
+ Note: This lists the catalog of available apps, not installed apps.
356
+
357
+ Examples:
358
+ # List all available apps
359
+ sumo-query list-apps
360
+
361
+ # Save to file
362
+ sumo-query list-apps --output apps.json
363
+ DESC
364
+ def list_apps
365
+ Commands::ListAppsCommand.new(options, create_client).execute
366
+ end
367
+
368
+ # ============================================================
369
+ # Content Library Commands (path-based)
370
+ # ============================================================
371
+
372
+ desc 'get-content', 'Get a content item by its library path'
373
+ long_desc <<~DESC
374
+ Look up a content item in the Sumo Logic content library by its path.
375
+ Returns the item ID, type, name, and parent folder.
376
+
377
+ Examples:
378
+ # Get content by path
379
+ sumo-query get-content --path '/Library/Users/me/My Saved Search'
380
+
381
+ # Save to file
382
+ sumo-query get-content --path '/Library/Users/me/Dashboard' --output content.json
383
+ DESC
384
+ option :path, type: :string, required: true, aliases: '-p', desc: 'Content library path'
385
+ # rubocop:disable Naming/AccessorMethodName -- Thor CLI command, not a getter
386
+ def get_content
387
+ Commands::GetContentCommand.new(options, create_client).execute
388
+ end
389
+ # rubocop:enable Naming/AccessorMethodName
390
+
391
+ desc 'export-content', 'Export a content item as JSON'
392
+ long_desc <<~DESC
393
+ Export a content library item (search, dashboard, folder) as JSON.
394
+ Handles the async export job automatically (start, poll, fetch result).
395
+
396
+ Examples:
397
+ # Export by content ID
398
+ sumo-query export-content --content-id 0000000000123456
399
+
400
+ # Save export to file
401
+ sumo-query export-content --content-id 0000000000123456 --output export.json
402
+ DESC
403
+ option :content_id, type: :string, required: true, desc: 'Content item ID to export'
404
+ def export_content
405
+ Commands::ExportContentCommand.new(options, create_client).execute
406
+ end
407
+
408
+ # ============================================================
409
+ # Utility Commands
410
+ # ============================================================
411
+
94
412
  desc 'version', 'Show version information'
95
413
  def version
96
414
  puts "sumo-query version #{Sumologic::VERSION}"