@specific.dev/cli 0.1.161 → 0.1.163

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 (89) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +2 -2
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +2 -2
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +1 -1
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_next/static/chunks/{d5bf905a3d3f005b.js → 03b7f2d1ca0f0722.js} +1 -1
  10. package/dist/admin/_next/static/chunks/{7e5c5b91b30c68a0.js → 6623aba8114d9978.js} +2 -2
  11. package/dist/admin/_not-found/__next._full.txt +1 -1
  12. package/dist/admin/_not-found/__next._head.txt +1 -1
  13. package/dist/admin/_not-found/__next._index.txt +1 -1
  14. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  15. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  16. package/dist/admin/_not-found/__next._tree.txt +1 -1
  17. package/dist/admin/_not-found/index.html +1 -1
  18. package/dist/admin/_not-found/index.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  20. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  21. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  22. package/dist/admin/databases/__next._full.txt +1 -1
  23. package/dist/admin/databases/__next._head.txt +1 -1
  24. package/dist/admin/databases/__next._index.txt +1 -1
  25. package/dist/admin/databases/__next._tree.txt +1 -1
  26. package/dist/admin/databases/index.html +1 -1
  27. package/dist/admin/databases/index.txt +1 -1
  28. package/dist/admin/fullscreen/__next._full.txt +2 -2
  29. package/dist/admin/fullscreen/__next._head.txt +1 -1
  30. package/dist/admin/fullscreen/__next._index.txt +1 -1
  31. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  32. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  33. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  39. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  40. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  41. package/dist/admin/fullscreen/databases/index.html +1 -1
  42. package/dist/admin/fullscreen/databases/index.txt +1 -1
  43. package/dist/admin/fullscreen/index.html +1 -1
  44. package/dist/admin/fullscreen/index.txt +2 -2
  45. package/dist/admin/index.html +1 -1
  46. package/dist/admin/index.txt +2 -2
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  48. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  49. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  50. package/dist/admin/mail/__next._full.txt +1 -1
  51. package/dist/admin/mail/__next._head.txt +1 -1
  52. package/dist/admin/mail/__next._index.txt +1 -1
  53. package/dist/admin/mail/__next._tree.txt +1 -1
  54. package/dist/admin/mail/index.html +1 -1
  55. package/dist/admin/mail/index.txt +1 -1
  56. package/dist/admin/services/__next.!KGRlZmF1bHQp.services.__PAGE__.txt +1 -1
  57. package/dist/admin/services/__next.!KGRlZmF1bHQp.services.txt +1 -1
  58. package/dist/admin/services/__next.!KGRlZmF1bHQp.txt +1 -1
  59. package/dist/admin/services/__next._full.txt +1 -1
  60. package/dist/admin/services/__next._head.txt +1 -1
  61. package/dist/admin/services/__next._index.txt +1 -1
  62. package/dist/admin/services/__next._tree.txt +1 -1
  63. package/dist/admin/services/index.html +1 -1
  64. package/dist/admin/services/index.txt +1 -1
  65. package/dist/admin/storage/__next.!KGRlZmF1bHQp.storage.__PAGE__.txt +2 -2
  66. package/dist/admin/storage/__next.!KGRlZmF1bHQp.storage.txt +1 -1
  67. package/dist/admin/storage/__next.!KGRlZmF1bHQp.txt +1 -1
  68. package/dist/admin/storage/__next._full.txt +2 -2
  69. package/dist/admin/storage/__next._head.txt +1 -1
  70. package/dist/admin/storage/__next._index.txt +1 -1
  71. package/dist/admin/storage/__next._tree.txt +1 -1
  72. package/dist/admin/storage/index.html +1 -1
  73. package/dist/admin/storage/index.txt +2 -2
  74. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  75. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  76. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  77. package/dist/admin/workflows/__next._full.txt +1 -1
  78. package/dist/admin/workflows/__next._head.txt +1 -1
  79. package/dist/admin/workflows/__next._index.txt +1 -1
  80. package/dist/admin/workflows/__next._tree.txt +1 -1
  81. package/dist/admin/workflows/index.html +1 -1
  82. package/dist/admin/workflows/index.txt +1 -1
  83. package/dist/cli.js +12 -3
  84. package/dist/docs/index.md +1 -0
  85. package/dist/docs/observability.md +192 -0
  86. package/package.json +1 -1
  87. /package/dist/admin/_next/static/{4_42SkCjqmgu0V3Wfnmok → EbVmgKWgDvW4075VZ1PdS}/_buildManifest.js +0 -0
  88. /package/dist/admin/_next/static/{4_42SkCjqmgu0V3Wfnmok → EbVmgKWgDvW4075VZ1PdS}/_clientMiddlewareManifest.json +0 -0
  89. /package/dist/admin/_next/static/{4_42SkCjqmgu0V3Wfnmok → EbVmgKWgDvW4075VZ1PdS}/_ssgManifest.js +0 -0
@@ -0,0 +1,192 @@
1
+ # Observability
2
+
3
+ Every deployed environment streams logs and metrics into a queryable store. Use `specific query` to run SQL against this data — useful for debugging production incidents, investigating regressions, and ad-hoc analytics.
4
+
5
+ ## Running a query
6
+
7
+ ```sh
8
+ # Inline
9
+ specific query "SELECT count() FROM observability.logs"
10
+
11
+ # Against a specific environment
12
+ specific query --environment staging "SELECT * FROM observability.logs LIMIT 5"
13
+
14
+ # From a file via stdin
15
+ cat queries/p99.sql | specific query
16
+ specific query - < queries/p99.sql
17
+ ```
18
+
19
+ Flags:
20
+
21
+ - `-e, --environment <name|id>` — target environment (defaults to the current one).
22
+
23
+ Queries are automatically scoped to the selected environment. You cannot see data from other environments and you do not need to filter on environment yourself.
24
+
25
+ Queries are read-only. `INSERT`, `UPDATE`, `DELETE`, and DDL are rejected. Each query is capped at 30 seconds of execution time, returns at most 100,000 rows, and the SQL string itself is limited to 50,000 characters.
26
+
27
+ ## Schema
28
+
29
+ Two views are exposed in the `observability` database.
30
+
31
+ ### `observability.logs`
32
+
33
+ Unified log stream from services.
34
+
35
+ | Column | Type | Notes |
36
+ |---|---|---|
37
+ | `Timestamp` | DateTime64(9) | When the log was emitted; use time arithmetic directly (`Timestamp > now() - INTERVAL 1 HOUR`) |
38
+ | `ServiceName` | String | Name of the service that emitted the log |
39
+ | `SeverityText` | String | |
40
+ | `SeverityNumber` | UInt8 | |
41
+ | `Body` | String | The log message |
42
+ | `LogAttributes` | Map(String, String) | Per-event attributes |
43
+ | `ResourceAttributes` | Map(String, String) | Resource labels (e.g. `service.name`, `service.namespace`, `deployment.environment.name`) |
44
+ | `TraceId` | String | Distributed-tracing trace ID, if present |
45
+ | `SpanId` | String | Distributed-tracing span ID, if present |
46
+
47
+ Also exposed but rarely queried directly: `EnvironmentId`, `ProjectId` (already used for auto-scoping), `TraceFlags`.
48
+
49
+ Retention: up to 30 days. Your plan may further restrict how far back queries can read; when that cutoff is in effect, `specific query` prints a one-line note on stderr.
50
+
51
+ ### `observability.metrics`
52
+
53
+ Unified metrics from services.
54
+
55
+ | Column | Type | Notes |
56
+ |---|---|---|
57
+ | `TimeUnix` | DateTime64(9) | Measurement timestamp; use time arithmetic directly (`TimeUnix > now() - INTERVAL 1 HOUR`) |
58
+ | `MetricName` | String | e.g. `container.cpu.time` (see list below) |
59
+ | `MetricType` | String | `'gauge'` or `'sum'` |
60
+ | `Value` | Float64 | Measured value |
61
+ | `ServiceName` | String | Service that emitted the metric |
62
+ | `Attributes` | Map(String, String) | Metric dimensions |
63
+ | `ResourceAttributes` | Map(String, String) | Resource labels |
64
+
65
+ Also exposed but rarely queried directly: `StartTimeUnix` (DateTime64(9)), `EnvironmentId`, `ProjectId`, `Source`.
66
+
67
+ Retention: up to 90 days. Your plan may further restrict how far back queries can read; when that cutoff is in effect, `specific query` prints a one-line note on stderr.
68
+
69
+ #### Service metrics
70
+
71
+ Emitted for every running service container.
72
+
73
+ | Metric | Type | Notes |
74
+ |---|---|---|
75
+ | `container.cpu.time` | sum | Cumulative CPU seconds consumed; rate it (`avg(Value)` over a window or per-second deltas) for utilisation |
76
+ | `container.cpu.usage` | gauge | Current CPU usage in cores |
77
+ | `container.cpu.limit_utilization` | gauge | Fraction of CPU limit used (0–1) |
78
+ | `container.memory.working_set` | gauge | Memory in active use (bytes) — the right number for "is this service close to OOM" |
79
+ | `container.memory.usage` | gauge | Total memory usage including page cache (bytes) |
80
+ | `container.memory.available` | gauge | Memory still available before the container limit (bytes) |
81
+ | `k8s.volume.available` | gauge | Free space on attached volumes (bytes) |
82
+ | `k8s.volume.capacity` | gauge | Total capacity of attached volumes (bytes) |
83
+
84
+ ## Debugging recipes
85
+
86
+ ### Recent errors for a specific service
87
+
88
+ ```sql
89
+ SELECT Timestamp, Body
90
+ FROM observability.logs
91
+ WHERE ServiceName = 'api'
92
+ AND SeverityNumber >= 17
93
+ AND Timestamp >= now() - INTERVAL 1 HOUR
94
+ ORDER BY Timestamp DESC
95
+ LIMIT 50
96
+ ```
97
+
98
+ ### Search log bodies for a substring
99
+
100
+ ```sql
101
+ SELECT Timestamp, ServiceName, Body
102
+ FROM observability.logs
103
+ WHERE positionCaseInsensitive(Body, 'connection refused') > 0
104
+ AND Timestamp >= now() - INTERVAL 6 HOUR
105
+ ORDER BY Timestamp DESC
106
+ LIMIT 100
107
+ ```
108
+
109
+ ### Warning-or-worse rate by service
110
+
111
+ ```sql
112
+ SELECT ServiceName, count() AS errs
113
+ FROM observability.logs
114
+ WHERE SeverityNumber >= 13
115
+ AND Timestamp >= now() - INTERVAL 1 HOUR
116
+ GROUP BY ServiceName
117
+ ORDER BY errs DESC
118
+ ```
119
+
120
+ ### Service CPU timeseries (1-minute buckets)
121
+
122
+ ```sql
123
+ SELECT
124
+ toStartOfMinute(TimeUnix) AS bucket,
125
+ avg(Value) AS cpu_cores
126
+ FROM observability.metrics
127
+ WHERE MetricName = 'container.cpu.usage'
128
+ AND ServiceName = 'api'
129
+ AND TimeUnix >= now() - INTERVAL 1 HOUR
130
+ GROUP BY bucket
131
+ ORDER BY bucket
132
+ ```
133
+
134
+ ### Memory headroom over time
135
+
136
+ ```sql
137
+ SELECT
138
+ TimeUnix,
139
+ ServiceName,
140
+ Value AS working_set_bytes
141
+ FROM observability.metrics
142
+ WHERE MetricName = 'container.memory.working_set'
143
+ AND TimeUnix >= now() - INTERVAL 30 MINUTE
144
+ ORDER BY TimeUnix
145
+ ```
146
+
147
+ ### Correlate all logs belonging to one trace
148
+
149
+ ```sql
150
+ SELECT Timestamp, ServiceName, Body
151
+ FROM observability.logs
152
+ WHERE TraceId = '<trace-id>'
153
+ ORDER BY Timestamp
154
+ ```
155
+
156
+ ## Performance
157
+
158
+ Both views are partitioned and ordered to make environment-scoped, time-bounded queries fast. To stay within the 30-second limit on large environments:
159
+
160
+ - **Always filter by time** — `Timestamp >=` for logs, `TimeUnix >=` for metrics. Unbounded scans across 30/90 days will time out.
161
+ - **Add `ServiceName` and/or `MetricName`** to narrow the partition further whenever you can.
162
+ - **`SELECT` only the columns you need** rather than `SELECT *`; `Body`, `LogAttributes`, and `ResourceAttributes` are the heavyweight columns.
163
+ - **`LIMIT` exploratory queries** while you're shaping them.
164
+
165
+ ## Discovering data
166
+
167
+ When you don't know what's there, ask the database:
168
+
169
+ ```sql
170
+ SHOW TABLES FROM observability;
171
+ DESCRIBE observability.logs;
172
+
173
+ SELECT DISTINCT ServiceName FROM observability.logs LIMIT 50;
174
+ SELECT DISTINCT MetricName FROM observability.metrics LIMIT 100;
175
+ ```
176
+
177
+ ## Useful ClickHouse functions
178
+
179
+ The store is ClickHouse, so the full ClickHouse SQL dialect is available. A few commonly needed functions:
180
+
181
+ - `now()`, `now64()` — current time
182
+ - `toStartOfMinute(t)`, `toStartOfFiveMinutes(t)`, `toStartOfHour(t)` — bucket timestamps for time-series aggregation
183
+ - `positionCaseInsensitive(haystack, needle)` — case-insensitive substring search
184
+ - `JSONExtractString(s, 'field')`, `JSONExtractInt`, `JSONExtractFloat` — pull fields out of JSON-formatted log bodies
185
+ - `LogAttributes['key']`, `Attributes['key']`, `ResourceAttributes['key']` — read map columns
186
+
187
+ ---
188
+
189
+ Related topics:
190
+
191
+ - Run `specific docs services` for how services are defined
192
+ - Run `specific docs postgres` for connecting to your application database (use `specific psql` for application data, not `specific query`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.161",
3
+ "version": "0.1.163",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",