Add OCI Logging: log groups, logs, ingestion, search - #423
Conversation
NitinKumar004
left a comment
There was a problem hiding this comment.
Review notes
Real data-plane engine (per #427): N/A.
CI: CodeQL fails — 2× high go/uncontrolled-allocation-size at providers/oci/logging/portable.go:225 and :263. Guard the size before allocating.
Findings
Medium · structure — STRUCTURE.md filename parity broken: provider group.go/log.go/ingestion.go+search.go vs wire groups.go/logs.go/dataplane.go
server/oci/logging/groups.go:1
If a maintainer navigates by the STRUCTURE.md filename convention -> they cannot map a feature's mock to its wire handler by a single filename, because logging pluralizes and merges wire filenames against the singular, split provider files (server/oci/logging/groups.go, logs.go, dataplane.go).
STRUCTURE.md §3 hard rule ('a feature uses the same filename across all three layers') is broken for all three feature areas: provider group.go/log.go/ingestion.go/search.go vs wire groups.go(plural)/logs.go(plural)/dataplane.go(ingestion+search merged). The vcn reference keeps identical names across layers (dhcp.go/dhcp.go, subnet.go/subnet.go), so logging is the outlier. Naming-only, no runtime impact.
Low · correctness — Log-group displayName uniqueness is global, not per-compartment — diverges from real OCI
providers/oci/logging/group.go:24
If a user creates identically-named log groups in two different compartments (normal in real OCI) -> the second create fails with AlreadyExists, because providers/oci/logging/group.go:24 enforces a global name index rather than a per-compartment one.
createGroup calls groupByName(spec.DisplayName), which scans ALL compartments and returns AlreadyExists on any name collision (UpdateGroup rename too). Real OCI scopes log-group displayName uniqueness per compartment. The 'already exists' test (logging_test.go:83) only covers a same-compartment duplicate; documented as a deliberate tradeoff in docs/services.md to let the portable driver key groups by name.
Low · coverage — Search sort-ordering and oracle. provenance where-fields have no positive test*
server/oci/logging/handler_test.go:467
If someone later refactors sortEntries or provenanceValue and flips the desc branch or mis-maps an oracle.* field -> the bug ships green, because no test exercises sort-desc ordering or a where oracle.logid = ... comparison.
TestSearchLogs covers whole-compartment, narrowed-to-log, where-on-JSON-field, wildcards, time-range miss, field-info; the rejection table covers bad sorts/operators/fields. Neither asserts a successful 'sort by datetime asc|desc' RESULT ORDER nor a where-clause on oracle.compartmentid/loggroupid/logid/ingestedtime. provider sortEntries(desc) and provenanceValue() thus have no positive assertion; provider pkg coverage is 66.8%.
Implements the portable logging driver against OCI Logging, with the OCI-only surface behind a consumer-side Extras interface. OCI publishes the service on three API surfaces, which collapse onto one CloudEmu server, so Matches claims each prefix's collections exactly: /20200531 for the log group and log control plane, /20200601 for the loggingingestion push, and /20190909 for loggingsearch. A top-level /logs collection belongs to the ingestion plane alone — the control plane nests logs under their log group — which is what keeps the two apart. A log group is the portable log group, a CUSTOM log is the log stream and an ingested entry is the log event. Every log group and log mutation is asynchronous in real OCI, so each answers 202 with an opc-work-request-id carrying the created resource's OCID. Ingesting into a SERVICE log or a disabled one is refused rather than accepted and dropped. Metric filters have no OCI equivalent and report Unimplemented. Search reads the straightforward query form — a search clause over compartment[/logGroup[/log]], an optional where clause of = and != comparisons joined by and, and an optional sort by datetime — and rejects everything else naming what it tripped on rather than returning an empty result set: the summarize, stats, topN and extract operators, or/not/parenthesized where clauses, the ordering and pattern operators, an unresolvable field, and a search target written as a name where OCI takes an OCID.
…tment Guard the caller-supplied read limit before it sizes an allocation: GetLogEvents, FilterLogEvents and SearchLogs now reject a negative limit and one above maxLogLimit with InvalidArgument. Resolves the CodeQL uncontrolled-allocation-size findings in portable.go. Scope log-group displayName uniqueness per compartment, as real OCI does. The portable driver has only a name to address a group by, so a name held in more than one compartment is rejected as ambiguous rather than resolved arbitrarily. Rename the wire files to match the provider's, per STRUCTURE.md section 3: groups.go -> group.go, logs.go -> log.go, and dataplane.go split into ingestion.go and search.go.
Implement snapshot.Snapshottable for the Logging mock, which the #582 completeness guard requires of any provider field holding a memstore — without it a stop/start silently dropped every log group, log and ingested entry. logRecord's fields are exported so the record round-trips through the generic memstore helper, which serializes as JSON. Subscription filters, added to the shared driver upstream, are not an OCI Logging operation: OCI delivers log entries to another service through a Service Connector, so all three report Unimplemented naming that rather than accepting a filter nothing would honour.
b155d84 to
86a227b
Compare
|
Rebased onto current CI — CodeQL
|
Summary
loggingdriver.services/logging/driver; OCI-only behaviour is a consumer-sideExtrasinterface, per Move OCI-only capabilities out of shared driver packages #393.Closes #414. Part of #376.
Changes
providers/oci/logging/—Mockovermemstoreimplementingdriver.Logging, guarded by async.RWMutex, plus a search-query parser.server/oci/logging/— the three-prefix wire surface.providers/oci/oci.goandserver/oci/oci.go.Operations
Control plane: Create/List/Get/Update/Delete LogGroup, ChangeLogGroupCompartment, Create/List/Get/Update/Delete Log. Data planes:
PutLogs,SearchLogs. All 14 portable driver methods implemented; metric filters returnUnimplementednaming Service Connectors as OCI's answer.The three prefixes — the main design risk
parsePathsplits/{version}/{collection}[/{id}[/{sub}[/{subId}]]], then a switch on version claims exactly one collection set:20200531→logGroups,unifiedAgentConfigurations,logSavedSearches;20200601→logs;20190909→search.The load-bearing detail: a top-level
/logscollection exists only on the ingestion prefix — the control plane nests logs under their group — so/20200531/logsis deliberately unclaimed.TestMatcheshas 25 cases covering every positive shape, each collection asserted not claimed under the two wrong prefixes, other services' traffic, and malformed paths.Search: supported vs rejected
Supported:
search "compartmentId[/logGroupId[/logId]]"(comma-separated targets)| where <field> = | != '<value>'(*wildcard, joined byand)| sort by datetime [asc|desc]. Fields resolve overlogContent.*anddata.<key>of a JSON payload.Rejected by name with a 400:
summarize/stats/topN/extract/unknown operators;or,not, parenthesized where clauses;>,<,>=,<=,=~,!~; unresolvable fields or nested payload paths; sorting on anything but datetime; a target written as a name where OCI takes an OCID; a missing search clause or time range.A real silent-empty bug was found and fixed mid-implementation: field resolution originally happened per-entry, so an unknown field on a log with no entries returned
200 []. Fields now resolve at parse time, before any entry is walked.Judgement calls
ListLogstakes nocompartmentId— real OCI derives it from the log group in the path, so the group OCID is what is required. Noted inservices.mdand the handler comment.RetentionDayshas somewhere to live.DeleteLogGroupcascades to its logs rather than refusing, matching the other portable drivers.Provider Coverage
Checklist
go test ./...) — exit 0, 272 packagesgolangci-lint run --timeout=9m) — 0 issuescloudemu_test.go— driver + handler tests insteadTest Plan
Coverage leak check clean: no OCI operation in
docs/coverage/{aws,azure,gcp}/*.md;git diff development -- services/empty.End-to-end on a running server (port 4615):
Left out
No
oci-go-sdkcompat test — the three-client split made the e2e transcript stronger evidence for the effort.oracle.tenantidis omitted from search records; adding it would pull config identity into the handler for no behavioural gain.