From 843aca23b212059ecc102a32e6c58f0cbab962bb Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 24 Jul 2026 14:46:14 +0500 Subject: [PATCH 1/2] update coding agents --- .opencode/agents/architect.md | 45 +++++++++ .opencode/agents/builder.md | 34 +++++++ .opencode/agents/code-reviewer.md | 46 +++++++++ .opencode/agents/coder.md | 46 +++++++++ .opencode/agents/explorer.md | 26 +++++ .opencode/agents/sanity-reviewer.md | 40 ++++++++ .opencode/agents/team-lead.md | 52 ++++++++++ .opencode/agents/tester.md | 36 +++++++ AGENTS.md | 16 +-- opencode.json | 151 +--------------------------- 10 files changed, 334 insertions(+), 158 deletions(-) create mode 100644 .opencode/agents/architect.md create mode 100644 .opencode/agents/builder.md create mode 100644 .opencode/agents/code-reviewer.md create mode 100644 .opencode/agents/coder.md create mode 100644 .opencode/agents/explorer.md create mode 100644 .opencode/agents/sanity-reviewer.md create mode 100644 .opencode/agents/team-lead.md create mode 100644 .opencode/agents/tester.md diff --git a/.opencode/agents/architect.md b/.opencode/agents/architect.md new file mode 100644 index 00000000..46cc90a2 --- /dev/null +++ b/.opencode/agents/architect.md @@ -0,0 +1,45 @@ +--- +mode: all +model: openai/gpt-5.5 +variant: high +description: Analyze requirements and produce C++ architecture and implementation instructions +permission: + read: allow + grep: allow + glob: allow + list: allow + edit: deny + task: + "*": deny + explorer: allow + bash: + "*": deny + "git log*": allow + "git diff*": allow +--- + +You are a C++ solution architect. Analyze and design; do not implement, build, or test. + +Discovery: +- Use @explorer for broad discovery when context is missing. +- Read files directly only to verify APIs, invariants, ownership/lifetime, or details needed for precise instructions. +- Do not repeat broad exploration already done by @explorer. + +Goal: +- Produce instructions precise enough for @coder to implement with a cheaper model and no architecture decisions. + +Required output: +1. Risk: High/Medium/Low, approval requirement, and reason. Low: comments, typos, tests only, or isolated implementation bugfix without API/behavior impact. Medium: behavior changes, cross-file refactors, async/task logic, build configuration, dependency configuration, or public headers without ABI concern. High: persistence/state format, crypto/security, ownership/lifetime, public API/ABI, threading/concurrency, cross-platform behavior, or dependency version changes. +2. Blocking Questions: none, or questions blocking implementation. +3. Decision: final design choice, short and direct. +4. Acceptance Criteria: observable behavior required. +5. Coder Packet: + - Files to Modify: exact edit allowlist and add/modify/delete intent. + - Implementation Steps: ordered concrete steps with files, symbols, and signatures where needed. + - Invariants: what must remain true. + - Do NOT Change: only non-obvious protected boundaries, not the rest of the project. + - Escalate If: when @coder must stop and return. + +Rules: +- Do not include build/test commands; @builder and @tester own validation. +- Request user approval for all Medium and High risk changes before implementation. diff --git a/.opencode/agents/builder.md b/.opencode/agents/builder.md new file mode 100644 index 00000000..e878e926 --- /dev/null +++ b/.opencode/agents/builder.md @@ -0,0 +1,34 @@ +--- +mode: subagent +model: openai/gpt-5.4-mini-fast +variant: low +description: Validate project build and analyze compiler logs +permission: + read: allow + edit: deny + bash: + "*": deny + "ninja*": allow + "cmake*": allow +temperature: 0.1 +steps: 5 +--- + +You are a C++ build validation specialist. + +Responsibilities: +- Run the requested CMake/Ninja build: full build, specific target, or configured build command. +- If the build succeeds, report the command, build directory, and success. +- If the build fails, analyze the full build log and report root-cause errors only. + +Failure analysis rules: +- Collapse cascaded diagnostics into the real underlying issue. +- Group independent failures by file, target, or symbol. +- For each issue, report location, root cause, and brief supporting diagnostic. + +Output: +- End every report with exactly one marker: Build validation: SUCCESS or Build validation: FAILURE. + +Rules: +- Do not edit files. +- Do not fix issues yourself. diff --git a/.opencode/agents/code-reviewer.md b/.opencode/agents/code-reviewer.md new file mode 100644 index 00000000..54731c60 --- /dev/null +++ b/.opencode/agents/code-reviewer.md @@ -0,0 +1,46 @@ +--- +mode: all +model: openai/gpt-5.5 +variant: high +description: Deep review of current task changes when final or high-risk validation is needed +permission: + read: allow + glob: allow + grep: allow + edit: deny + bash: + "*": deny + "git log*": allow + "git diff*": allow +temperature: 0.1 +--- + +You are a strict C++ deep code reviewer for final/high-risk validation. + +Scope: +- Review only current task files from @coder's changed-file list. +- Use actual diffs and relevant surrounding code only as needed. +- Ignore unrelated dirty worktree changes, generated artifacts, temp files, and logs. + +Source of truth: +- User request, architect Decision, Acceptance Criteria, Coder Packet, Invariants, Do NOT Change, @sanity-reviewer result, and @coder Intentional tradeoffs. + +Review focus: +- Correctness, UB, lifetime/ownership, async/task usage, persistence, CMake target propagation, cross-platform desktop/IoT behavior, performance, and security. + +Design/tradeoff rules: +- Do not redesign the solution. +- Do not reject intentional performance/API ergonomics tradeoffs only because a safer alternative exists. +- Treat tradeoffs as Findings only for concrete correctness, security, lifetime, ownership, requirement, or invariant violations. +- If an intentional API/performance tradeoff can be misused but matches accepted architecture, report it as Design Risk instead of asking for a coder patch. + +Clang-tidy/suppression review: +- Review suppressions, NOLINT, disabled checks, and unresolved clang-tidy findings. +- Treat unjustified suppressions as Findings; justification must be performance, API ergonomics, intended behavior, or project conventions. + +Rules: +- Never edit files. +- Mark repeated or design-level issues as Block. +- When blocking on design-level issues, state that architect revision is required rather than recommending local coder patching. + +Output: Reviewed files, Findings, Design risks, Suppression review, Missing tests, Risk assessment, Approve or Block. diff --git a/.opencode/agents/coder.md b/.opencode/agents/coder.md new file mode 100644 index 00000000..0817df15 --- /dev/null +++ b/.opencode/agents/coder.md @@ -0,0 +1,46 @@ +--- +mode: subagent +model: openai/gpt-5.4-mini +variant: low +description: Write c++ code +permission: + edit: allow + grep: allow + bash: + "*": deny + "rm *": ask + "rm *.txt": ask + "rm *.cpp": allow + "rm *.h": allow + "rm *.hpp": allow + "rm *.cmake": allow + external_directory: deny + repo_clone: deny +--- + +You are a focused C++ implementation agent. Implement only @architect's Coder Packet; do not design or infer missing architecture from prose. + +Coder Packet contract: +- Files to Modify is the edit allowlist. Touch only those files unless @architect revises the packet. +- Execute Implementation Steps in numbered order. +- Preserve Invariants and never touch Do NOT Change items. +- Stop and report that revised @architect instructions are required if required files/APIs/steps are missing, contradictory, incompatible with code, match Escalate If, change approved design, or repeat the same failed issue. + +Implementation rules: +- Follow AGENTS.md, preserve existing patterns, avoid unrelated refactors, keep changes minimal. +- Follow code-style related to .clang-format and run clang-format after each change. +- Do not run or request build/test validation. + +Clang-tidy rules: +- Fix @sanity-reviewer clang-tidy findings as much as possible. +- Leave a finding unresolved only when fixing it harms performance, API ergonomics, intended behavior, or project conventions. +- For every unresolved finding, add an appropriate suppression or report why unresolved. +- Explain each suppression/unresolved finding briefly. +- Report suppressions or intentional performance/API ergonomics tradeoffs under: Intentional tradeoffs. + +Output: +- Report what changed and let @team-lead coordinate validation. +- Changed files: added, modified, deleted, or renamed files you changed only, with summary per file. +- Intentional tradeoffs: performance/API ergonomics/suppression decisions, or none. +- Verification: always state not run by coder. +- Notes: blockers, pre-existing unrelated worktree changes noticed, or none. diff --git a/.opencode/agents/explorer.md b/.opencode/agents/explorer.md new file mode 100644 index 00000000..ef794aae --- /dev/null +++ b/.opencode/agents/explorer.md @@ -0,0 +1,26 @@ +--- +mode: subagent +model: openai/gpt-5.4-mini-fast +variant: low +description: Read-only codebase exploration before architecture or implementation work +permission: + edit: deny + bash: deny + grep: allow + glob: allow + list: allow + read: allow + external_directory: deny +temperature: 0.1 +--- + +You are a read-only C++ codebase explorer. + +Responsibilities: +- Find relevant files, APIs, existing patterns, build targets, tests, and constraints for the requested change. +- Return concise facts with file paths and symbols that @architect and @coder can rely on. + +Rules: +- Do not design the solution. +- Do not edit files. +- Do not build or test. diff --git a/.opencode/agents/sanity-reviewer.md b/.opencode/agents/sanity-reviewer.md new file mode 100644 index 00000000..fc5f5671 --- /dev/null +++ b/.opencode/agents/sanity-reviewer.md @@ -0,0 +1,40 @@ +--- +mode: subagent +model: openai/gpt-5.4-mini +variant: low +description: Fast check that implementation matches the task and proposed architecture +permission: + read: allow + glob: allow + grep: allow + edit: deny + bash: + "*": deny + "clang-tidy*": allow + "git log*": allow + "git diff*": allow +temperature: 0.1 +--- + +You are a fast implementation sanity reviewer. + +Scope: +- Review only @coder's changed-file list for the current task. +- Use actual diffs for those files. +- Ignore unrelated worktree changes unless listed by @coder or explicitly assigned to this task. + +Checks: +- Verify changes match the user request and architect instructions. +- Find missing requested behavior, unrelated changes inside reviewed files, architecture mismatches, and incomplete implementation. +- Run clang-tidy on changed C++ source/header files using project .clang-tidy. +- Use AGENTS.md/project instructions to find build dir or compile_commands.json; prefer clang-tidy -p . +- If clang-tidy cannot run because compile database/build configuration is missing or stale, report Clang-tidy infrastructure blocked, not a coder issue. +- Ignore or separately report unrelated existing clang-tidy findings outside the reviewed changed files. +- Order clang-tidy findings from critical correctness to style/readability, grouping cascades by root cause. + +Rules: +- Do not perform deep C++ design review. +- Do not review generated artifacts, temp files, logs, or unrelated files. +- Never edit files. + +Output: Reviewed files, Matches task, Matches architecture, Clang-tidy findings, Blocking mismatches, Approve or Block. diff --git a/.opencode/agents/team-lead.md b/.opencode/agents/team-lead.md new file mode 100644 index 00000000..e7c22a81 --- /dev/null +++ b/.opencode/agents/team-lead.md @@ -0,0 +1,52 @@ +--- +mode: primary +model: openai/gpt-5.5-fast +variant: medium +description: The main agent to rule the others on the way to work on code. +permission: + edit: deny + bash: deny + task: allow +temperature: 0.1 +--- + +You are team-manager. Coordinate agents; do not edit code, build, or test directly. + +Agents: +- @explorer: read-only facts. +- @architect: design, Risk, Blocking Questions, Decision, Acceptance Criteria, Coder Packet. +- @coder: implements only the Coder Packet. +- @sanity-reviewer: task/architecture match plus clang-tidy on changed files. +- @builder: CMake/Ninja build validation. +- @tester: unit and smoke tests. +- @code-reviewer: deep review only when needed. + +Handoff rules: +- Run workflow stages sequentially, each only after the previous stage successfully finishes. +- Do not invoke @coder until @architect produced a complete Coder Packet with no Blocking Questions. +- If the Coder Packet is vague, incomplete, or missing files/steps, send it back to @architect before coding. +- You may do lightweight read-only inspection for routing, but prefer @explorer for repository context. + +Fast workflow: +1. Analyze request; use @explorer for unfamiliar areas, multi-file changes, public API, ownership/lifetime, async/task logic, or unknown target files. Skip @explorer only for trivial localized requests with explicit files. +2. Ask @architect for Risk, Blocking Questions, Decision, Acceptance Criteria, and Coder Packet. +3. Require user approval for medium/high-risk changes. +4. Ask @coder to implement the complete Coder Packet. +5. Ask @sanity-reviewer to check @coder Changed files; ignore unrelated worktree changes. +6. Sanity implementation/clang-tidy block -> @coder. Sanity architecture block -> @architect. +7. Ask @builder to validate build. Build failure -> @coder. +8. If build succeeds, ask @tester to run tests. Test failure -> @coder. +9. For small fixes, user-review loops, and tuning, stop after @tester success and report to user. + +Deep review policy: +- Do not run @code-reviewer during fast iteration unless user asks for deep/final review. +- For non-final fast iteration, if a change qualifies for deep review, ask the user whether to run @code-reviewer now or defer it to final validation. +- Run @code-reviewer after build/test success for final validation, High risk changes, public API, persistence, async/task flow, crypto/security, CMake, ownership/lifetime, or cross-platform behavior. If @sanity-reviewer reported an architecture mismatch during the task, run @code-reviewer after the revised implementation passes build/test. +- Pass @code-reviewer: user request, architect Decision/Acceptance Criteria/Coder Packet, @coder Changed files, @sanity-reviewer result, and @coder Intentional tradeoffs. +- Deep review block -> @architect, then continue with @coder -> @sanity-reviewer -> @builder -> @tester, and optional final @code-reviewer. + +Loop control: +- Max three fast fix cycles per task: @coder -> @sanity-reviewer -> @builder -> @tester. +- Any return to @coder after implementation counts as one fix cycle. +- Escalate to @architect after three failed cycles, repeated @code-reviewer issue, ambiguous coder instructions, approved-design change, or design/API/ownership/lifetime/CMake/requirement mismatch. +- If @architect changes an approved medium/high-risk design, request user approval again before invoking @coder. diff --git a/.opencode/agents/tester.md b/.opencode/agents/tester.md new file mode 100644 index 00000000..980e53ac --- /dev/null +++ b/.opencode/agents/tester.md @@ -0,0 +1,36 @@ +--- +mode: subagent +model: openai/gpt-5.4-mini-fast +variant: low +description: Run tests and analyze results +permission: + edit: deny + read: allow + grep: allow + glob: allow + bash: + "*": deny + "rm -rf *state": allow + "*aether-client-cpp-cloud*": allow + "ninja test": allow + "ctest *": allow +temperature: 0.1 +steps: 5 +--- + +You are a fast test runner and test result reporter. + +Responsibilities: +- Run unit tests. +- Separately run smoke tests. +- Report what passed and what failed. + +Smoke tests: +- Before running smoke tests, inspect project instructions such as AGENTS.md to identify what this project defines as smoke tests, where they must be run from, and whether cleanup is required. + +Failure reports: +- Report failing command, relevant output, exit status if available, and a short likely cause. + +Rules: +- Do not edit files. +- Do not design new tests unless explicitly asked. diff --git a/AGENTS.md b/AGENTS.md index bf045824..b61a5ac8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,9 +9,9 @@ - Always wrap `if` and `for` bodies in `{}` even if it's short one-line statement. - Initialize variables and objects using `{}` to distinguish from function call. - *Exception vector initialization*: In case vector must be created with size use `()` initialization to distinguish from initializer_list constructor. -- Always there is possible use `auto` for variables with respect for references `auto&` and pointers `auto*`. +- Use `auto` whenever possible for variables with respect for references `auto&` and pointers `auto*`. - Check if pointer is null by comparing it to `nullptr` instead of using implicit conversion to `bool`. -- If function arguments is not used, there are two options. If it's never used, just ommit the argument name. If it's used on some configurations use `[[maybe_unused]]` attribute. +- If a function argument is not used, there are two options. If it's never used, just ommit the argument name. If it's used on some configurations use `[[maybe_unused]]` attribute. - Immediate lambda call pattern should be implemented by using `std::invoke`. ## Architecture & Object System @@ -31,7 +31,7 @@ - Events uses SmallFunction as a callback storage. - Prefer setup SmallFunction by MethodPtr<&Class::method>{this} instead of lambda. - Event subscriptions should be stored in Subscription or MultiSubscriptions class members to control subscription lifetime. -- If the class makes subscription controls lifetime of the object with event, subscription objects maybe ommited. +- If the class makes subscription controls lifetime of the object with event, subscription objects maybe omitted. ## Asynchrony & Tasks @@ -53,13 +53,13 @@ - constructors are `ex::just()`, `ex::create()` or some custom senders created for specific logic. - adapters are `ex::then()`, `ex::let_value()`, `ex::let_error()`, `ex::upon_error()` and others that transform or combine senders. - consumers are `ex::sync_wait`, but preferred to use `ex::AnyWaiter` or `ex:AsyncWaiter`. -- se `ex::create` to create a sender from a functor to integrate c-style callbacks or other non sender logic into the executor. +- use `ex::create` to create a sender from a functor to integrate c-style callbacks or other non sender logic into the executor. - use `ex::create` if logic must test the value and set either error or value during runtime -- use `ex::variant_sender` to conditionally return either on or another sender based on some value. +- use `ex::variant_sender` to conditionally return either one sender or another based on some value. - use `ex::then` `ex::upon_error` to transform from one value to another or from error to value. - use `ex::let_value` to run new sender in chain in case of set_value. - use `ex::let_error` to run new sender in chain in case of set_error. -- `ex::for_range` to iterate over a range of values. Internal sender must return a value, an error or stopped to end loop. To cont +- `ex::for_range` to iterate over a range of values. Internal sender must return a value, an error or stopped to end loop. - `ex::with_timeout` to add timeout to a sender chain. - senders and adapters chained together by `|` operator. @@ -69,7 +69,7 @@ - The `Action` maybe inherited from `Action` class which adds `is_finished()` and `finished_event()` methods. - Each action should provide events to notify about operation progress and completion. Usually just `result_event()`. - Actions may use senders inside to define their logic or just subscribe to another action's events. -- Actions should be managed by the class that creates them and returned by reference or pointers in case of possible null. +- Actions should be managed by the class that creates them and returned by reference or pointers when null is possible. - If action `is_finished()` or after `finished_event()` is emitted non should have access to the action except the owner. - Actions may be created as class members with optional or `ActionPool` or `std::unique_ptr`. But prefer to avoid allocations. @@ -114,7 +114,7 @@ The first smoke test is a `/aether-client-cpp-cloud`. To run it simply `cd ` and ran the `./aether-client-cpp-cloud` binary. Notice! Run `aether-client-cpp-cloud` generates `state` dir there object state is saved. - Remove this `state` dir before run to make clean run. Keep it to run with previous state. + Remove this `state` dir before run to make clean run. Keep it to run with previous saved state. ## Operational Rules diff --git a/opencode.json b/opencode.json index bbe8a84d..df64ef17 100644 --- a/opencode.json +++ b/opencode.json @@ -2,154 +2,5 @@ "$schema": "https://opencode.ai/config.json", "model": "openai/gpt-5.5-fast", "small_model": "openai/gpt-5.4-mini-fast", - "default_agent": "team-lead", - "agent": { - "team-lead": { - "mode": "primary", - "model": "openai/gpt-5.5-fast", - "reasoningEffort": "medium", - "description": "The main agent to rule the others on the way to work on code.", - "prompt": "You are team-manager. You do not write code, build, or test directly. You coordinate specialized agents: @explorer finds relevant files and facts; @architect designs the solution and writes implementation instructions; @coder edits code from precise instructions; @builder validates CMake/Ninja builds and reports compiler or linker errors; @tester runs unit/smoke tests and reports results; @sanity-reviewer performs a fast task/architecture match check and clang-tidy check; @code-reviewer performs deep final code review. Coordination rule: run workflow stages sequentially. Never start @tester in the same step or same tool batch as @builder. Start @tester only after you have received a successful @builder report for the current implementation. Workflow: analyze the request; use @explorer when code context is needed; ask @architect for design and coder checklist; require user approval for medium/high-risk changes; ask @coder to implement; ask @builder to validate the build; if @builder reports build failure, send the report back to @coder and repeat; after build validation succeeds, ask @tester to run tests; if tests fail, send the report back to @coder and repeat build and tests; after tests pass, ask @sanity-reviewer for a fast task/architecture match check and clang-tidy check using the changed-file list reported by @coder, and tell @sanity-reviewer to ignore unrelated worktree changes outside that list; if sanity review blocks because of implementation mismatch or clang-tidy findings, route the issue to @coder; if sanity review blocks because of architecture mismatch, route the issue to @architect, then rebuild and retest; only after sanity review approves, ask @code-reviewer for deep final review; if deep review blocks, route directly to @architect for revised instructions, then continue with @coder, @builder, @tester, @sanity-reviewer, and @code-reviewer again. Loop control: allow at most three implementation fix cycles for the same task. A fix cycle is @coder -> @builder -> @tester -> @sanity-reviewer -> @code-reviewer. After three failed cycles, or immediately when failures indicate design/API/ownership/lifetime/CMake/requirement mismatch, escalate to @architect to rethink the solution before more coding. If @code-reviewer reports the same issue twice, escalate to @architect. If @coder says the instructions are ambiguous or the fix would change the approved design, escalate to @architect.", - "permission": { - "edit": "deny", - "bash": "deny", - "task": "allow" - }, - "temperature": 0.1 - }, - "explorer": { - "mode": "subagent", - "model": "openai/gpt-5.4-mini-fast", - "reasoningEffort": "low", - "description": "Read-only codebase exploration before architecture or implementation work", - "prompt": "You are a read-only C++ codebase explorer. Your task is to find relevant files, APIs, existing patterns, build targets, tests, and constraints for the requested change. Do not design the solution, do not edit files, do not build, and do not test. Return concise facts with file paths and symbols that @architect and @coder can rely on.", - "permission": { - "edit": "deny", - "bash": "deny", - "grep": "allow", - "glob": "allow", - "list": "allow", - "read": "allow", - "external_directory": "deny" - }, - "temperature": 0.1 - }, - "architect": { - "mode": "all", - "model": "openai/gpt-5.5", - "reasoningEffort": "high", - "description": "Analyze requirements and produce C++ architecture and implementation instructions", - "prompt": "You are a solution architect. You do not write code, build, or test. Use @explorer first for broad codebase discovery when relevant context is missing. After @explorer reports, read files directly only to verify exact APIs, invariants, ownership/lifetime behavior, or details needed for precise implementation instructions. Avoid repeating broad exploration already completed by @explorer. Produce practical architecture and precise implementation instructions for @coder. Include: files to inspect or modify, exact API or behavior changes, invariants to preserve, tests or build commands expected, risks, and things not to change. For medium or high-risk changes involving public APIs, persistence, async/task flow, crypto/security, platform behavior, or CMake structure, explicitly request user approval before implementation.", - "permission": { - "edit": "deny", - "task": { - "*": "deny", - "explorer": "allow" - }, - "bash": { - "*": "deny", - "git log*": "allow", - "git diff*": "allow" - } - } - }, - "coder": { - "mode": "subagent", - "model": "openai/gpt-5.5-fast", - "reasoningEffort": "low", - "description": "Write c++ code", - "prompt": "You are a focused C++ implementation agent. You receive precise instructions from @team-lead or @architect and implement only those instructions. Follow AGENTS.md, preserve existing style, avoid unrelated refactors, and keep changes minimal. If instructions are ambiguous, ask for clarification instead of inventing architecture. If a fix requires changing the architect-approved design or you are making a repeated attempt at the same failed issue, stop and ask @architect for revised instructions. When fixing clang-tidy findings from @sanity-reviewer, evaluate each warning before changing code. Fix warnings that indicate correctness, safety, portability, performance, or maintainability problems. Suppress or decline warnings only when the fix would harm performance, API ergonomics, intended behavior, or project conventions; explain each suppression or declined warning briefly. Do not run or request build/test validation. After implementation, report what changed and let @team-lead coordinate validation. At the end of your response, report the actual files you changed under: Changed files. Include added, modified, deleted, or renamed files. Do not include files changed by other agents or the user.", - "permission": { - "edit": "allow", - "grep": "allow", - "bash": { - "*": "deny", - "rm *": "ask", - "rm *.txt": "ask", - "rm *.cpp": "allow", - "rm *.h": "allow", - "rm *.hpp": "allow", - "rm *.cmake": "allow" - }, - "external_directory": "deny", - "repo_clone": "deny" - } - }, - "builder": { - "mode": "subagent", - "model": "openai/gpt-5.4-mini-fast", - "reasoningEffort": "low", - "description": "Validate project build and analyze compiler logs", - "prompt": "You are a C++ build validation specialist. Run the requested CMake/Ninja build: full build, specific target, or configured build command. If the build succeeds, report the command, build directory, and success. If the build fails, analyze the full build log and report root-cause errors only. Collapse cascaded diagnostics into the real underlying issue. Group independent failures by file, target, or symbol. For each issue, report the location, root cause, and brief supporting diagnostic. End every report with exactly one marker: Build validation: SUCCESS or Build validation: FAILURE. Do not edit files and do not fix issues yourself.", - "permission": { - "edit": "deny", - "bash": { - "*": "deny", - "ninja*": "allow", - "cmake*": "allow" - } - }, - "temperature": 0.1, - "steps": 5 - }, - "tester": { - "mode": "subagent", - "model": "openai/gpt-5.4-mini-fast", - "reasoningEffort": "low", - "description": "Run tests and analyze results", - "prompt": "You are a fast test runner and test result reporter. Run tests only after @builder has reported build success for the current implementation. If build success is not confirmed in the current workflow, report that testing is blocked by missing build validation and do not run tests. Your task is to run unit tests and separately run smoke tests, then report what passed and what failed. Before running smoke tests, inspect project instructions such as AGENTS.md to identify what this project defines as smoke tests, where they must be run from, and whether any cleanup is required. If a test fails, report the failing command, relevant output, exit status if available, and a short likely cause. Do not edit files and do not design new tests unless explicitly asked.", - "permission": { - "edit": "deny", - "read": "allow", - "grep": "allow", - "glob": "allow", - "bash": { - "*": "deny", - "rm -rf *state": "allow", - "*aether-client-cpp-cloud*": "allow", - "ninja test": "allow", - "ctest *": "allow" - } - }, - "temperature": 0.1, - "steps": 5 - }, - "sanity-reviewer": { - "mode": "subagent", - "model": "openai/gpt-5.4-mini", - "reasoningEffort": "low", - "description": "Fast check that implementation matches the task and proposed architecture", - "prompt": "You are a fast implementation sanity reviewer. Review only the files listed in the changed-file list provided by @coder for the current task. Use the actual diff for those files to verify what changed. Ignore other modified files in the worktree unless they are explicitly included in @coder's changed-file list or explicitly assigned to this task. Check whether the reviewed changes match the user request and architect instructions. Check for missing requested behavior, unrelated changes within the reviewed files, obvious mismatches with the proposed architecture, and incomplete implementation. Run clang-tidy on changed C++ source/header files from the reviewed file list using the project's .clang-tidy configuration. Use AGENTS.md or project instructions to find the build directory or compile_commands.json. Prefer running clang-tidy with -p pointing to the configured build directory when available. Report clang-tidy findings ordered from critical correctness issues to style/readability issues. Group repeated or cascaded warnings by root cause. Do not perform deep C++ design review. Do not review generated build artifacts, temporary files, logs, or unrelated files. Never edit files. Report: Reviewed files, Matches task, Matches architecture, Clang-tidy findings, Blocking mismatches, Approve or Block.", - "permission": { - "read": "allow", - "glob": "allow", - "grep": "allow", - "edit": "deny", - "bash": { - "*": "deny", - "clang-tidy*": "allow", - "git log*": "allow", - "git diff*": "allow" - } - }, - "temperature": 0.1 - }, - "code-reviewer": { - "mode": "all", - "model": "openai/gpt-5.5", - "reasoningEffort": "high", - "description": "Review code and validate if it solves the problem", - "prompt": "You are a strict C++ code reviewer. Review the current code diff against the user request and architect instructions. Focus on correctness, undefined behavior, object lifetime, ownership, async/task usage, persistence, CMake target propagation, cross-platform desktop/IoT behavior, performance, and security. Review any clang-tidy suppressions, NOLINT comments, disabled checks, or declined clang-tidy findings. Verify each suppression is justified by performance, API ergonomics, intended behavior, or project conventions. Treat unjustified suppressions as Findings. Do not review generated build artifacts, temporary files, logs, or unrelated files. Never edit files. Mark repeated or design-level issues as Block. When you Block, route the issue to @architect for revised instructions rather than recommending a local coder fix. Report: Findings, Missing tests, Risk assessment, Approve or Block.", - "permission": { - "grep": "allow", - "edit": "deny", - "bash": { - "*": "deny", - "git log*": "allow", - "git diff*": "allow" - } - }, - "temperature": 0.1 - } - } + "default_agent": "team-lead" } From b224678077a5f5fa23db8eb3b24d59626eba841e Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 27 Jul 2026 11:50:35 +0500 Subject: [PATCH 2/2] update tele to use it from external repo --- CMakeLists.txt | 11 +- aether/CMakeLists.txt | 4 - aether/aether_tele.h | 6 +- aether/tele.h | 2 +- aether/tele/collectors.h | 202 -------- aether/tele/compile_option.h | 35 -- aether/tele/configs/all_enabled.h | 49 -- aether/tele/defines.h | 82 ---- aether/tele/env/compiler.h | 68 --- aether/tele/env/cpu_architecture.h | 142 ------ aether/tele/env/library_version.h | 33 -- aether/tele/env/platform_type.h | 47 -- aether/tele/env_collectors.h | 103 ---- aether/tele/itrap.h | 114 ----- aether/tele/levels.h | 58 --- aether/tele/modules.h | 37 -- aether/tele/sink.h | 80 ---- aether/tele/tags.h | 78 --- aether/tele/tele.h | 38 -- aether/tele/traps/io_stream_traps.cpp | 156 ------ aether/tele/traps/io_stream_traps.h | 76 --- aether/tele/traps/proxy_trap.h | 60 --- aether/tele/traps/statistics_trap.cpp | 158 ------- aether/tele/traps/statistics_trap.h | 227 --------- aether/tele_compile_options.h | 2 +- aether/tele_statistics.h | 2 +- tests/CMakeLists.txt | 1 - tests/test-object-system/CMakeLists.txt | 7 +- tests/test-tele/CMakeLists.txt | 46 -- tests/test-tele/test-tele.cpp | 602 ------------------------ 30 files changed, 17 insertions(+), 2509 deletions(-) delete mode 100644 aether/tele/collectors.h delete mode 100644 aether/tele/compile_option.h delete mode 100644 aether/tele/configs/all_enabled.h delete mode 100644 aether/tele/defines.h delete mode 100644 aether/tele/env/compiler.h delete mode 100644 aether/tele/env/cpu_architecture.h delete mode 100644 aether/tele/env/library_version.h delete mode 100644 aether/tele/env/platform_type.h delete mode 100644 aether/tele/env_collectors.h delete mode 100644 aether/tele/itrap.h delete mode 100644 aether/tele/levels.h delete mode 100644 aether/tele/modules.h delete mode 100644 aether/tele/sink.h delete mode 100644 aether/tele/tags.h delete mode 100644 aether/tele/tele.h delete mode 100644 aether/tele/traps/io_stream_traps.cpp delete mode 100644 aether/tele/traps/io_stream_traps.h delete mode 100644 aether/tele/traps/proxy_trap.h delete mode 100644 aether/tele/traps/statistics_trap.cpp delete mode 100644 aether/tele/traps/statistics_trap.h delete mode 100644 tests/test-tele/CMakeLists.txt delete mode 100644 tests/test-tele/test-tele.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 76f2806c..ed9e877b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,7 @@ CPMAddPackage( NAME numeric GIT_REPOSITORY "https://github.com/aethernetio/aethernet-numeric.git" GIT_TAG "main" - OPTIONS "AE_NUMERIC_INSTALL ${AE_INSTALL}" + OPTIONS "AE_NUMERIC_INSTALL ${AE_INSTALL}" "AE_BUILD_TESTS ${AE_BUILD_TESTS}" EXCLUDE_FROM_ALL FALSE ) CPMAddPackage( @@ -140,6 +140,14 @@ CPMAddPackage( OPTIONS "AE_INSTALL ${AE_INSTALL}" "AE_BUILD_TESTS ${AE_BUILD_TESTS}" EXCLUDE_FROM_ALL FALSE ) +CPMAddPackage( + NAME aether-tele + GIT_REPOSITORY "https://github.com/aethernetio/aether-tele.git" + GIT_TAG "main" + OPTIONS "AE_TELE_INSTALL ${AE_INSTALL}" + "AE_TELE_BUILD_TESTS ${AE_BUILD_TESTS}" + EXCLUDE_FROM_ALL FALSE +) CPMAddPackage( NAME etl GIT_REPOSITORY "https://github.com/ETLCPP/etl.git" @@ -166,6 +174,7 @@ target_include_directories(${TARGET_NAME} PUBLIC $ ) target_link_libraries(${TARGET_NAME} PUBLIC + aether-tele bcrypt sodium hydrogen diff --git a/aether/CMakeLists.txt b/aether/CMakeLists.txt index e5576f34..e3bf7de7 100644 --- a/aether/CMakeLists.txt +++ b/aether/CMakeLists.txt @@ -231,8 +231,4 @@ list(APPEND aether_srcs "channels/lora_module_channel.cpp" "channels/modem_channel.cpp") -list(APPEND aether_srcs - "tele/traps/io_stream_traps.cpp" - "tele/traps/statistics_trap.cpp") - target_sources(${TARGET_NAME} PRIVATE ${aether_srcs}) diff --git a/aether/aether_tele.h b/aether/aether_tele.h index 2eb40307..ebabde73 100644 --- a/aether/aether_tele.h +++ b/aether/aether_tele.h @@ -19,10 +19,10 @@ #include +#include "aether-tele/levels.h" +#include "aether-tele/sink.h" +#include "aether-tele/tags.h" #include "aether/config.h" -#include "aether/tele/levels.h" -#include "aether/tele/sink.h" -#include "aether/tele/tags.h" namespace ae { namespace aether_tele_internal { diff --git a/aether/tele.h b/aether/tele.h index 5b313bf3..ac8a5911 100644 --- a/aether/tele.h +++ b/aether/tele.h @@ -25,7 +25,7 @@ #endif #define TELE_SINK ::ae::tele::TeleSink<::ae::AetherTeleConfig> -#include "aether/tele/tele.h" +#include "aether-tele/tele.h" // IWYU pragma: end_keeps #endif // AETHER_TELE_H_ diff --git a/aether/tele/collectors.h b/aether/tele/collectors.h deleted file mode 100644 index fc18060f..00000000 --- a/aether/tele/collectors.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_COLLECTORS_H_ -#define AETHER_TELE_COLLECTORS_H_ - -#include -#include -#include -#include -#include -#include - -#include "aether-miscpp/format/format.h" - -#include "aether/tele/itrap.h" -#include "aether/tele/levels.h" -#include "aether/tele/modules.h" // IWYU pragma: keep -#include "aether/tele/sink.h" -#include "aether/tele/tags.h" - -namespace ae::tele { -namespace collectors_internal { -struct EmptyNull { - template - constexpr explicit EmptyNull(Args&&...) noexcept {} -}; - -template -struct OrEmpty { - using type = std::conditional_t; -}; - -static constexpr inline auto kEmptyFormat = FormatScheme{""}; -} // namespace collectors_internal - -template -using OrEmpty_t = - typename collectors_internal::OrEmpty::type; - -struct Timer { - Duration elapsed() const { - auto d = TimePoint::clock::now() - start; - return std::chrono::duration_cast(d); - } - - TimePoint const start{TimePoint::clock::now()}; -}; - -struct TimedTele { - Timer timer; - Tag const& tag; - std::shared_ptr trap; -}; - -template -static constexpr inline bool kIsAnyLogs = Config.logs_enabled; - -template -static constexpr inline bool kIsAnyMetrics = - Config.count_metrics || Config.time_metrics; - -template -static constexpr inline bool kIsAnyTele = - kIsAnyLogs || kIsAnyMetrics; - -template -struct TeleLogCollector; - -// Specialization for disabled Logs -template -struct TeleLogCollector>> final - : public ILogCollector { - template - constexpr explicit TeleLogCollector(TArgs&&...) noexcept {} - - void WriteLine(ILogLine&) override {} -}; - -// Specialization for enabled Logs -template -struct TeleLogCollector>> final - : public ILogCollector { - static constexpr auto SinkConfig = Config; - - template - constexpr explicit TeleLogCollector(Tag const& t, Level l, std::string_view f, - std::uint32_t f_l, - std::span b) noexcept - : tag{t}, level{l}, file{f}, line{f_l}, blob{b} {} - - void WriteLine([[maybe_unused]] ILogLine& log_line) override { - if constexpr (SinkConfig.start_time_logs) { - log_line.InvokeTime(TimePoint::clock::now()); - } - if constexpr (SinkConfig.level_module_logs) { - log_line.WriteLevel(level); - log_line.WriteModule(tag.module); - } - if constexpr (SinkConfig.location_logs) { - log_line.Location(file, line); - } - if constexpr (SinkConfig.name_logs) { - log_line.TagName(tag.name); - } - if constexpr (SinkConfig.blob_logs) { - log_line.Blob(blob); - } - } - - [[no_unique_address]] OrEmpty_t< - SinkConfig.level_module_logs || SinkConfig.name_logs, Tag const&> tag; - [[no_unique_address]] OrEmpty_t level; - [[no_unique_address]] OrEmpty_t - file; - [[no_unique_address]] OrEmpty_t line; - [[no_unique_address]] OrEmpty_t> blob; -}; - -// Dummy Tele if telemetry is disabled -template -struct Tele { - template - constexpr explicit Tele(TArgs&&... /* args */) {} -}; - -// Tele for enabled telemetry -template -struct Tele>> { - using Sink = TSink; - static constexpr auto SinkConfig = Config; - using TimedTele = OrEmpty_t; - - template - constexpr Tele(Sink& sink, Tag const& tag, [[maybe_unused]] Level level, - [[maybe_unused]] std::string_view file, - [[maybe_unused]] int line, - [[maybe_unused]] FormatScheme const format = - collectors_internal::kEmptyFormat, - [[maybe_unused]] BlobArgs&&... args) noexcept - : timed_tele_{std::invoke([&]() -> TimedTele { - if constexpr (SinkConfig.time_metrics) { - return TimedTele{.timer = {}, .tag = tag, .trap = sink.trap()}; - } else { - return TimedTele{}; - } - })} { - auto trap = sink.trap(); - if (!trap) { - return; - } - if constexpr (SinkConfig.count_metrics) { - trap->AddInvoke(tag, 1); - } - - if constexpr (kIsAnyLogs) { - // TODO: more effective way to make blob - std::string blob_str; - std::span blob{}; - if constexpr (SinkConfig.blob_logs) { - if (format.source != collectors_internal::kEmptyFormat.source) { - FormatTo(blob_str, format, std::forward(args)...); - blob = {reinterpret_cast(blob_str.data()), - blob_str.size()}; - } - } - auto collector = TeleLogCollector{ - tag, level, file, static_cast(line), blob}; - trap->LogLine(tag, collector); - } - } - - ~Tele() { - if constexpr (SinkConfig.time_metrics) { - if (!timed_tele_.trap) { - return; - } - timed_tele_.trap->AddInvokeDuration(timed_tele_.tag, - timed_tele_.timer.elapsed()); - } - } - - private: - [[no_unique_address]] TimedTele timed_tele_; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_COLLECTORS_H_ diff --git a/aether/tele/compile_option.h b/aether/tele/compile_option.h deleted file mode 100644 index 263534dc..00000000 --- a/aether/tele/compile_option.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_COMPILE_OPTION_H_ -#define AETHER_TELE_COMPILE_OPTION_H_ - -#include -#include - -namespace ae::tele { -struct CompileOption { - std::uint32_t index; - std::string_view name; - std::string_view value; -}; - -struct CustomOption { - std::string_view name; - std::string_view value; -}; -} // namespace ae::tele -#endif // AETHER_TELE_COMPILE_OPTION_H_ */ diff --git a/aether/tele/configs/all_enabled.h b/aether/tele/configs/all_enabled.h deleted file mode 100644 index 5c76460e..00000000 --- a/aether/tele/configs/all_enabled.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2026 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_CONFIGS_ALL_ENABLED_H_ -#define AETHER_TELE_CONFIGS_ALL_ENABLED_H_ - -#include - -#include "aether/tele/levels.h" -#include "aether/tele/sink.h" - -namespace ae::tele { -struct AllEnabledConfig { - template - static consteval auto GetTeleConfig() { - return TeleConfig{ - .count_metrics = true, - .time_metrics = true, - .logs_enabled = true, - .start_time_logs = true, - .level_module_logs = true, - .location_logs = true, - .name_logs = true, - .blob_logs = true, - }; - } - static consteval auto GetEnvConfig() { - return EnvConfig{ - .static_info = true, - .runtime_info = true, - }; - } -}; -} // namespace ae::tele - -#endif // AETHER_TELE_CONFIGS_ALL_ENABLED_H_ diff --git a/aether/tele/defines.h b/aether/tele/defines.h deleted file mode 100644 index d7582d3c..00000000 --- a/aether/tele/defines.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_DEFINES_H_ -#define AETHER_TELE_DEFINES_H_ - -// IWYU pragma: begin_keeps -#include "aether/tele/collectors.h" -#include "aether/tele/env_collectors.h" -#include "aether/tele/modules.h" -#include "aether/tele/tags.h" -// IWYU pragma: end_keeps - -#define AETE_CAT_(A, B) A##B -#define AETE_CAT(A, B) AETE_CAT_(A, B) -#define AETE_UNIQUE_NAME(P) AETE_CAT(P, AETE_CAT(__LINE__, __COUNTER__)) - -#ifndef UTM_ID -# define UTM_ID 0 -#endif - -// namespace ae::tele { -// using ae::tele::EnvTele; -// using ae::tele::Tele; -// } // namespace ae::tele - -// A special tag for telemetry debug debug - -AE_TELE_MODULE(MLog, AE_LOG_MODULE, AE_LOG_MODULE, AE_LOG_MODULE); -AE_TAG(kLog, MLog) - -#define AE_TELE_(TAG_NAME, TAG, LEVEL, ...) \ - [[maybe_unused]] auto TAG_NAME = ::ae::tele::Tele< \ - TELE_SINK, TELE_SINK::template GetTeleConfig()> { \ - TELE_SINK::Instance(), TAG, ::ae::tele::Level{LEVEL}, __FILE__, __LINE__, \ - __VA_ARGS__ \ - } - -#define AE_TELE_DEBUG(TAG, ...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), TAG, ::ae::tele::Level::kDebug, __VA_ARGS__) -#define AE_TELE_INFO(TAG, ...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), TAG, ::ae::tele::Level::kInfo, __VA_ARGS__) -#define AE_TELE_WARNING(TAG, ...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), TAG, ::ae::tele::Level::kWarning, \ - __VA_ARGS__) -#define AE_TELE_ERROR(TAG, ...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), TAG, ::ae::tele::Level::kError, __VA_ARGS__) - -// For simple logging -#define AE_TELED_DEBUG(...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), kLog, ::ae::tele::Level::kDebug, \ - __VA_ARGS__) -#define AE_TELED_INFO(...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), kLog, ::ae::tele::Level::kInfo, __VA_ARGS__) -#define AE_TELED_WARNING(...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), kLog, ::ae::tele::Level::kWarning, \ - __VA_ARGS__) -#define AE_TELED_ERROR(...) \ - AE_TELE_(AETE_UNIQUE_NAME(TELE_), kLog, ::ae::tele::Level::kError, \ - __VA_ARGS__) - -// Log environment data -#define AE_TELE_ENV(...) \ - [[maybe_unused]] auto AETE_UNIQUE_NAME(TELE_ENV_) = \ - ::ae::tele::EnvTele { \ - TELE_SINK::Instance(), UTM_ID, __VA_ARGS__ \ - } - -#endif // AETHER_TELE_DEFINES_H_ */ diff --git a/aether/tele/env/compiler.h b/aether/tele/env/compiler.h deleted file mode 100644 index 74805086..00000000 --- a/aether/tele/env/compiler.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ENV_COMPILER_H_ -#define AETHER_TELE_ENV_COMPILER_H_ - -#define AETE_QUOTE(x) #x - -#define AETE_STR(x) AETE_QUOTE(x) - -#define _AETE_CONCAT_0(A, B, ...) A##B -#define _AETE_CONCAT_1(A, ...) __CONCAT_0(A##__VA_ARGS__) -#define _AETE_CONCAT_2(A, ...) _AETE_CONCAT_1(A##__VA_ARGS__) -#define _AETE_CONCAT_3(A, ...) _AETE_CONCAT_2(A##__VA_ARGS__) -#define _AETE_CONCAT_N(_3, _2, _1, _0, X, ...) _AETE_CONCAT##X(_3, _2, _1, _0) -#define AETE_CONCAT(...) _AETE_CONCAT_N(__VA_ARGS__, _2, _1, _0) - -#if defined __clang__ -# if defined __MINGW32__ -# define COMPILER "mingw clang" -# else -# define COMPILER "clang" -# endif -# define COMPILER_VERSION \ - AETE_STR(__clang_major__) \ - "." AETE_STR(__clang_minor__) "." AETE_STR(__clang_patchlevel__) -# define COMPILER_VERSION_NUM \ - AE_CONCAT(__clang_major__, __clang_minor__, __clang_patchlevel__) -#elif defined __GNUC__ -# if defined __MINGW32__ -# define COMPILER "mingw gcc" -# else -# define COMPILER "gcc" -# endif -# define COMPILER_VERSION \ - AETE_STR(__GNUC__) \ - "." AETE_STR(__GNUC_MINOR__) "." AETE_STR(__GNUC_PATCHLEVEL__) -# define COMPILER_VERSION_NUM \ - AE_CONCAT(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#elif defined _MSC_VER -# define COMPILER "msvc" -# define COMPILER_VERSION AETE_STR(_MSC_FULL_VER) -# define COMPILER_VERSION_NUM _MSC_FULL_VER -#else -# warning "unknown compiler" -# define COMPILER "unknown" -# if defined __VERSION__ -# define COMPILER_VERSION __VERSION__ -# else -# define COMPILER_VERSION "unknown" -# define COMPILER_VERSION_NUM 0 -# endif -#endif - -#endif // AETHER_TELE_ENV_COMPILER_H_ */ diff --git a/aether/tele/env/cpu_architecture.h b/aether/tele/env/cpu_architecture.h deleted file mode 100644 index 7e43f8d3..00000000 --- a/aether/tele/env/cpu_architecture.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ENV_CPU_ARCHITECTURE_H_ -#define AETHER_TELE_ENV_CPU_ARCHITECTURE_H_ - -#if defined ESP_PLATFORM -# include -# define AE_CPU_TYPE CONFIG_IDF_TARGET -#endif - -#if !defined AE_CPU_TYPE -# if defined GEKKO -# define AE_CPU_TYPE "IBM PowerPC 750 (NGC)" -# endif - -# if defined mc68000 || defined m68k || defined __MC68K__ || defined m68000 -# define AE_CPU_TYPE "MC68000" -# endif - -# if defined __PPC__ || defined __POWERPC__ || defined powerpc || \ - defined _POWER || defined __ppc__ || defined __powerpc__ -# if defined __powerpc64__ -# define AE_CPU_TYPE "PowerPC64" -# else -# define AE_CPU_TYPE "PowerPC" -# endif -# endif - -# if defined _CRAYT3E || defined _CRAYMPP -/* target processor is a DEC Alpha 21164 used in a Cray T3E*/ -# define AE_CPU_TYPE "Cray T3E (Alpha 21164)" -# endif - -# if defined CRAY || defined _CRAY && !defined _CRAYT3E -# error Non-AXP Cray systems not supported -# endif - -# if defined _SH3 -# define AE_CPU_TYPE "Hitachi SH-3" -# endif - -# if defined __sh4__ || defined __SH4__ -# define AE_CPU_TYPE "Hitachi SH-4" -# endif - -# if defined __sparc__ || defined __sparc -# if defined __arch64__ || defined __sparcv9 || defined __sparc_v9__ -# define AE_CPU_TYPE "Sparc/64" -# else -# define AE_CPU_TYPE "Sparc/32" -# endif -# endif - -# if defined(ARM) || defined(__arm__) || defined(_ARM) -# define AE_CPU_TYPE "ARM" -# elif defined(__ARM_ARCH_2__) -# define AE_CPU_TYPE "ARM2"; -# elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) -# define AE_CPU_TYPE "ARM3"; -# elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T) -# define AE_CPU_TYPE "ARM4T"; -# elif defined(__ARM_ARCH_5_) || defined(__ARM_ARCH_5E_) -# define AE_CPU_TYPE "ARM5" -# elif defined(__ARM_ARCH_6T2_) || defined(__ARM_ARCH_6T2_) -# define AE_CPU_TYPE "ARM6T2"; -# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ - defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ - defined(__ARM_ARCH_6ZK__) -# define AE_CPU_TYPE "ARM6"; -# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ - defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \ - defined(__ARM_ARCH_7S__) -# define AE_CPU_TYPE "ARM7"; -# elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ - defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) -# define AE_CPU_TYPE "ARM7A"; -# elif defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \ - defined(__ARM_ARCH_7S__) -# define AE_CPU_TYPE "ARM7R"; -# elif defined(__ARM_ARCH_7M__) -# define AE_CPU_TYPE "ARM7M"; -# elif defined(__ARM_ARCH_7S__) -# define AE_CPU_TYPE "ARM7S"; -# elif defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) -# define AE_CPU_TYPE "ARM64"; -# endif - -# if defined mips || defined __mips__ || defined __MIPS__ || defined _MIPS -# if defined _R5900 -# define AE_CPU_TYPE "MIPS R5900 (PS2)" -# else -# define AE_CPU_TYPE "MIPS" -# endif -# endif - -# if defined __ia64 || defined _M_IA64 || defined __ia64__ -# define AE_CPU_TYPE "IA64" -# endif - -# if defined __X86__ || defined __i386__ || defined i386 || \ - defined _M_IX86 || defined __386__ || defined __x86_64__ || \ - defined _M_X64 -# if defined __x86_64__ || defined _M_X64 -# define AE_CPU_TYPE "AMD x86-64" -# else -# define AE_CPU_TYPE "Intel 386+" -# endif -# endif - -# if defined __alpha || defined alpha || defined _M_ALPHA || defined __alpha__ -# define AE_CPU_TYPE "AXP" -# endif - -# if defined __hppa || defined hppa -# define AE_CPU_TYPE "PA-RISC" -# endif - -# if defined __riscv -# define AE_CPU_TYPE "RISCV" -# endif -#endif - -#if !defined AE_CPU_TYPE -# warning Unable to determine CPU type -# define AE_CPU_TYPE "Unknown" /* this is here for Doxygen's benefit */ -#endif - -#endif // AETHER_TELE_ENV_CPU_ARCHITECTURE_H_ */ diff --git a/aether/tele/env/library_version.h b/aether/tele/env/library_version.h deleted file mode 100644 index 06845279..00000000 --- a/aether/tele/env/library_version.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ENV_LIBRARY_VERSION_H_ -#define AETHER_TELE_ENV_LIBRARY_VERSION_H_ - -#if defined AE_GIT_VERSION -# define LIBRARY_VERSION AE_PROJECT_VERSION "." AE_GIT_VERSION -#elif defined AE_PROJECT_VERSION -# define LIBRARY_VERSION AE_PROJECT_VERSION -#else -# define LIBRARY_VERSION "0.0.0" -# if defined _MSC_VER -# pragma message("Library version is not defined.") -# else -# warning "Library version is not defined." -# endif -#endif - -#endif // AETHER_TELE_ENV_LIBRARY_VERSION_H_ */ diff --git a/aether/tele/env/platform_type.h b/aether/tele/env/platform_type.h deleted file mode 100644 index d8f9d9fa..00000000 --- a/aether/tele/env/platform_type.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ENV_PLATFORM_TYPE_H_ -#define AETHER_TELE_ENV_PLATFORM_TYPE_H_ - -#if !defined AE_PLATFORM_TYPE -# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) -# define AE_PLATFORM_TYPE "Windows" -# elif defined(__linux__) || defined(__gnu_linux__) -# define AE_PLATFORM_TYPE "Linux" -# elif defined(__FreeBSD__) -# define AE_PLATFORM_TYPE "FreeBSD" -# elif defined __APPLE__ -# include -# if TARGET_OS_IPHONE -# define AE_PLATFORM_TYPE "IOS" -# elif TARGET_OS_MAC -# define AE_PLATFORM_TYPE "macOs" -# endif -# elif defined __ANDROID__ -# define AE_PLATFORM_TYPE "Android" -# elif defined ESP_PLATFORM -# include -# define AE_PLATFORM_TYPE CONFIG_IDF_TARGET -# else -# warning "Unknown platform" -# warning \ - "Please define AE_PLATFORM_TYPE to name your platform in statistics" -# define AE_PLATFORM_TYPE "Unknown" -# endif -#endif - -#endif // AETHER_TELE_ENV_PLATFORM_TYPE_H_ */ diff --git a/aether/tele/env_collectors.h b/aether/tele/env_collectors.h deleted file mode 100644 index 1f21adc6..00000000 --- a/aether/tele/env_collectors.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ENV_COLLECTORS_H_ -#define AETHER_TELE_ENV_COLLECTORS_H_ - -#include -#include -#include - -#include "aether/env.h" -#include "aether/tele/compile_option.h" -#include "aether/tele/env/compiler.h" -#include "aether/tele/env/cpu_architecture.h" -#include "aether/tele/env/library_version.h" -#include "aether/tele/env/platform_type.h" -#include "aether/tele/itrap.h" -#include "aether/tele/sink.h" - -namespace ae::tele { -/** - * Collect environment information about application - * - Build data - * - compiler - * - compiler version - * - compilation options (enabled crypto flags, enabled telemetry, debug and - * distillation modes) - * - library version (git hash and git origin remote url) - * - API version - * - Target platform info - * - OS type - * - chip type - * - architecture - */ - -constexpr auto PlatformType() { return AE_PLATFORM_TYPE; } -constexpr auto CompilerName() { return COMPILER; } -constexpr auto CompilerVersion() { return COMPILER_VERSION; } -constexpr auto LibraryVersion() { return LIBRARY_VERSION; } - -constexpr Endianness PlatformEndianness() { - return static_cast(AE_ENDIANNESS); -} -constexpr auto CpuType() { return AE_CPU_TYPE; } - -template -struct EnvTele { - template - constexpr explicit EnvTele(TArgs&&... /* args */) {} -}; - -template -struct EnvTele> { - using Sink = TSink; - static constexpr auto SinkConfig = Config; - - template - explicit EnvTele( - Sink& sink, [[maybe_unused]] std::uint32_t utm_id, - [[maybe_unused]] std::array const& - compile_options = {}, - [[maybe_unused]] std::array const& - custom_options = {}) { - auto env_data = EnvData{}; - - if constexpr (SinkConfig.static_info) { - env_data.platform_type = PlatformType(); - env_data.compiler = CompilerName(); - env_data.compiler_version = CompilerVersion(); - env_data.library_version = LibraryVersion(); - env_data.cpu_arch = CpuType(); - env_data.endianness = PlatformEndianness(); - env_data.utm_id = utm_id; - env_data.compile_options = std::span{compile_options}; - } - if constexpr (SinkConfig.runtime_info) { - env_data.custom_options = std::span{custom_options}; - } - auto& trap = sink.trap(); - if (!trap) { - return; - } - trap->WriteEnvData(env_data); - } -}; - -} // namespace ae::tele - -#endif // AETHER_TELE_ENV_COLLECTORS_H_ */ diff --git a/aether/tele/itrap.h b/aether/tele/itrap.h deleted file mode 100644 index 47396ba0..00000000 --- a/aether/tele/itrap.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2025 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_ITRAP_H_ -#define AETHER_TELE_ITRAP_H_ - -#include -#include -#include -#include - -#include "aether/tele/compile_option.h" -#include "aether/tele/levels.h" -#include "aether/tele/modules.h" -#include "aether/tele/tags.h" - -namespace ae::tele { - -using TimePoint = std::chrono::system_clock::time_point; -using Duration = std::chrono::microseconds; - -enum class Endianness : std::uint8_t { Little = 1, Big }; - -struct EnvData { - std::string_view platform_type; - std::string_view compiler; - std::string_view compiler_version; - std::string_view library_version; - std::string_view cpu_arch; - Endianness endianness; - std::uint32_t utm_id; - std::span compile_options; - std::span custom_options; -}; - -class ILogLine { - protected: - ~ILogLine() = default; - - public: - /** - * \brief Telemetry invoke time. - */ - virtual void InvokeTime(TimePoint time) = 0; - /** - * \brief Telemetry tag level - */ - virtual void WriteLevel(Level level) = 0; - /** - * \brief Tag module - */ - virtual void WriteModule(Module const& module) = 0; - /** - * \brief Tag location - */ - virtual void Location(std::string_view file, std::uint32_t line) = 0; - /** - * \brief Tag name - */ - virtual void TagName(std::string_view name) = 0; - /** - * \brief Get stream to write telemetry blob data. - */ - virtual void Blob(std::span blob) = 0; -}; - -// Collects logs and write them to the LogLine -class ILogCollector { - protected: - ~ILogCollector() = default; - - public: - virtual void WriteLine(ILogLine& log_line) = 0; -}; - -/** - * \brief Telemetry trap interaface. - */ -class ITrap { - public: - virtual ~ITrap() = default; - /** - * \brief Invoke count for metrics - */ - virtual void AddInvoke(Tag const& tag, std::uint32_t count) = 0; - /** - * \brief Invoke duration for metrics - */ - virtual void AddInvokeDuration(Tag const& tag, Duration duration) = 0; - /** - * \brief Write collected log. - */ - virtual void LogLine(Tag const& tag, ILogCollector& log_collector) = 0; - /** - * \brief Write an environment data - */ - virtual void WriteEnvData(EnvData const& env_data) = 0; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_ITRAP_H_ diff --git a/aether/tele/levels.h b/aether/tele/levels.h deleted file mode 100644 index deb0d142..00000000 --- a/aether/tele/levels.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_LEVELS_H_ -#define AETHER_TELE_LEVELS_H_ - -#include -#include - -namespace ae::tele { -struct Level { - using underlined_t = std::uint8_t; - enum LevelVariant : std::uint8_t { // NOLINT(*use-enum-class*) - kInfo = 1 << 0, - kWarning = 1 << 1, - kError = 1 << 2, - kDebug = 1 << 3, - kAll = 0xFF, - }; - - std::string_view Text() const { - switch (value_) { - case kInfo: - return "kInfo"; - case kWarning: - return "kWarning"; - case kError: - return "kError"; - case kDebug: - return "kDebug"; - default: - break; - } - return ""; - } - - operator underlined_t() const noexcept { // NOLINT(*explicit*) - return value_; - } - - underlined_t value_; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_LEVELS_H_ */ diff --git a/aether/tele/modules.h b/aether/tele/modules.h deleted file mode 100644 index b90d2c3b..00000000 --- a/aether/tele/modules.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_MODULES_H_ -#define AETHER_TELE_MODULES_H_ - -#include -#include - -namespace ae::tele { -struct Module { - std::uint32_t id; - std::uint32_t index_start; - std::uint32_t index_end; - std::string_view name; -}; -} // namespace ae::tele - -#define AE_TELE_MODULE(NAME, ID, INDEX_START, INDEX_END) \ - inline constexpr auto NAME = ae::tele::Module { \ - ID, INDEX_START, INDEX_END, #NAME \ - } - -#endif // AETHER_TELE_MODULES_H_ diff --git a/aether/tele/sink.h b/aether/tele/sink.h deleted file mode 100644 index 01803c21..00000000 --- a/aether/tele/sink.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_SINK_H_ -#define AETHER_TELE_SINK_H_ - -#include -#include - -#include "aether/tele/itrap.h" -#include "aether/tele/levels.h" -#include "aether/tele/modules.h" // IWYU pragma: keep - -namespace ae::tele { -struct TeleConfig { - bool count_metrics = true; - bool time_metrics = true; - - bool logs_enabled = true; - bool start_time_logs = true; - bool level_module_logs = true; - bool location_logs = true; - bool name_logs = true; - bool blob_logs = true; -}; - -struct EnvConfig { - bool static_info = true; - bool runtime_info = true; -}; - -template -concept ConfigProvider = requires() { - { - T::template GetTeleConfig() - } -> std::same_as; - { T::GetEnvConfig() } -> std::same_as; -}; - -template -class TeleSink { - public: - using ConfigProviderType = CP; - - template - static consteval auto GetTeleConfig() { - return ConfigProviderType::template GetTeleConfig(); - } - static consteval auto GetEnvConfig() { - return ConfigProviderType::GetEnvConfig(); - } - - static TeleSink& Instance() { - static TeleSink sink; - return sink; - } - - constexpr void SetTrap(std::shared_ptr const& trap) { trap_ = trap; } - - constexpr auto const& trap() const { return trap_; } - - private: - std::shared_ptr trap_; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_SINK_H_ diff --git a/aether/tele/tags.h b/aether/tele/tags.h deleted file mode 100644 index 857bfb82..00000000 --- a/aether/tele/tags.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_TAGS_H_ -#define AETHER_TELE_TAGS_H_ - -#include -#include - -#include "aether-miscpp/crc.h" // IWYU pragma: keep -#include "aether/tele/modules.h" - -namespace ae::tele { -namespace tags_internal { -template -inline constexpr std::uint32_t kAeTagIndexCounter = - kAeTagIndexCounter; -template -inline constexpr std::uint32_t kAeTagIndexCounter = - static_cast(0 - 1); -} // namespace tags_internal - -// Telemetry tag -struct Tag { - constexpr std::uint32_t index() const { return module.index_start + offset; } - - std::uint32_t offset; - Module const& module; - std::string_view name; -}; -} // namespace ae::tele - -// NOLINTBEGIN -#define _AE_CRC(LITERAL) ::crc32::checksum_from_literal(LITERAL) - -#define _AE_FILE_TAG(MODULE) _AE_CRC(__FILE__ #MODULE) -#define _AE_INDEX __LINE__ -#define _AE_NEXT_INDEX (__LINE__ + 1) - -#define _AE_TAG_INDEX_GET(MODULE) \ - ::ae::tele::tags_internal::kAeTagIndexCounter<_AE_FILE_TAG(MODULE), _AE_INDEX> - -#define _AE_TAG_INDEX_WRITE(MODULE, VALUE) \ - template <> \ - inline constexpr auto ::ae::tele::tags_internal::kAeTagIndexCounter< \ - _AE_FILE_TAG(MODULE), _AE_NEXT_INDEX> = std::uint32_t{VALUE}; - -/** - * \brief Register Tag with index specified - */ -#define AE_TAG_INDEXED(NAME, MODULE, INDEX) \ - inline constexpr auto NAME = ::ae::tele::Tag{(INDEX), (MODULE), #NAME}; \ - _AE_TAG_INDEX_WRITE(MODULE, (NAME).offset) \ - static_assert(((MODULE).index_start + (NAME).offset) <= (MODULE).index_end, \ - "Tag index out of range"); - -// NOLINTEND - -/** - * \brief Register Tag with index automatically incremented from previous - * AE_TAG* call - */ -#define AE_TAG(NAME, MODULE) \ - AE_TAG_INDEXED(NAME, MODULE, _AE_TAG_INDEX_GET(MODULE) + 1) -#endif // AETHER_TELE_TAGS_H_ diff --git a/aether/tele/tele.h b/aether/tele/tele.h deleted file mode 100644 index 6f99a802..00000000 --- a/aether/tele/tele.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_TELE_H_ -#define AETHER_TELE_TELE_H_ - -// IWYU pragma: begin_exports -#include "aether/tele/configs/all_enabled.h" -#include "aether/tele/defines.h" -#include "aether/tele/modules.h" -#include "aether/tele/sink.h" -#include "aether/tele/tags.h" -#include "aether/tele/traps/io_stream_traps.h" -#include "aether/tele/traps/proxy_trap.h" -#include "aether/tele/traps/statistics_trap.h" -// IWYU pragma: end_exports - -#define DEFAULT_SINK ::ae::tele::TeleSink<::ae::tele::AllEnabledConfigProvider> - -// redefine this macro to use your own sink -#ifndef TELE_SINK -# define TELE_SINK DEFAULT_SINK -#endif - -#endif // AETHER_TELE_TELE_H_ diff --git a/aether/tele/traps/io_stream_traps.cpp b/aether/tele/traps/io_stream_traps.cpp deleted file mode 100644 index f0d9944e..00000000 --- a/aether/tele/traps/io_stream_traps.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define AETHER_TELE_TELE_H_ - -#include "aether/tele/traps/io_stream_traps.h" - -#include -#include - -#include "aether-miscpp/format/format.h" - -namespace ae::tele { -namespace { - -void WriteUnformatted(std::ostream& stream, std::string_view value) { - stream.write(value.data(), static_cast(value.size())); -} - -void WritePaddedIndex(std::ostream& stream, std::uint32_t index) { - static constexpr auto kPaddings = " "; - static constexpr auto kSteps = 3; - - auto decs = std::invoke([&]() noexcept { - std::uint32_t delim = 10; - for (auto i = 0; i < kSteps; ++i) { - auto d = index / delim; - if (d == 0) { - return i; - } - delim = delim * delim; - } - return kSteps; - }); - stream.write(kPaddings, kSteps - decs); - Format(stream, "{}", index); -} - -} // namespace - -IoStreamTrap::LogLineWriter::LogLineWriter(std::ostream& s, Tag const& tag) - : stream_{s} { - WritePaddedIndex(stream_, tag.index()); -} - -void IoStreamTrap::LogLineWriter::InvokeTime(TimePoint time) { - Format(stream_, ":[{:time}]", time); -} -void IoStreamTrap::LogLineWriter::WriteLevel(Level level) { - stream_.put(':'); - WriteUnformatted(stream_, level.Text()); -} -void IoStreamTrap::LogLineWriter::WriteModule(Module const& module) { - stream_.put(':'); - WriteUnformatted(stream_, module.name); -} -void IoStreamTrap::LogLineWriter::Location(std::string_view file, - std::uint32_t line) { - auto pos = file.find_last_of("/\\"); - if (pos != std::string_view::npos) { - file = file.substr(pos + 1, file.size() - pos); - } else { - file = "UNKNOWN FILE"; - } - Format(stream_, ":{}:{}", file, line); -} -void IoStreamTrap::LogLineWriter::TagName(std::string_view name) { - stream_.put(':'); - WriteUnformatted(stream_, name); -} -void IoStreamTrap::LogLineWriter::Blob(std::span blob) { - if (blob.empty()) { - return; - } - stream_.put(':'); - stream_.write(reinterpret_cast(blob.data()), - static_cast(blob.size())); -} - -IoStreamTrap::IoStreamTrap(std::ostream& stream) : stream_{stream} {} - -IoStreamTrap::~IoStreamTrap() { - auto lock = std::scoped_lock{sync_lock_}; - WriteUnformatted(stream_, "Metrics:\n"); - WriteUnformatted( - stream_, "Index,Invocations,Max Duration,Sum Duration,Min Duration\n"); - for (auto const& [index, ms] : metrics_) { - Format(stream_, "{},{},{},{},{}\n", index, ms.invocations_count, - ms.max_duration, ms.sum_duration, ms.min_duration); - } - stream_.put('\n'); - stream_.flush(); -} - -void IoStreamTrap::AddInvoke(Tag const& tag, std::uint32_t count) { - auto lock = std::scoped_lock{sync_lock_}; - metrics_[tag.index()].invocations_count += count; -} - -void IoStreamTrap::AddInvokeDuration(Tag const& tag, Duration duration) { - auto lock = std::scoped_lock{sync_lock_}; - auto& metric = metrics_[tag.index()]; - metric.max_duration = std::max(metric.max_duration, - static_cast(duration.count())); - metric.sum_duration += duration.count(); - if (metric.min_duration == 0) { - metric.min_duration = static_cast(duration.count()); - } else { - metric.min_duration = std::min( - metric.min_duration, static_cast(duration.count())); - } -} - -void IoStreamTrap::LogLine(Tag const& tag, ILogCollector& log_collector) { - auto lock = std::scoped_lock{sync_lock_}; - auto log_line = LogLineWriter(stream_, tag); - log_collector.WriteLine(log_line); - stream_.put('\n'); - stream_.flush(); -} - -void IoStreamTrap::WriteEnvData(EnvData const& env_data) { - auto lock = std::scoped_lock{sync_lock_}; - Format(stream_, - "Platform:{}\nCompiler:{}\nCompiler version:{}\nLibrary " - "version:{}\nCPU arch:{}\nEndianness:{}\nUTMid:{}\n", - env_data.platform_type, env_data.compiler, env_data.compiler_version, - env_data.library_version, env_data.cpu_arch, - (env_data.endianness == Endianness::Little ? "LittleEndian" - : "BigEndian"), - env_data.utm_id); - constexpr auto option_format = FormatScheme{"{}:{}\n"}; - for (auto const& opt : env_data.compile_options) { - Format(stream_, option_format, opt.name, opt.value); - } - for (auto const& opt : env_data.custom_options) { - Format(stream_, option_format, opt.name, opt.value); - } - stream_.put('\n'); - stream_.flush(); -} - -} // namespace ae::tele diff --git a/aether/tele/traps/io_stream_traps.h b/aether/tele/traps/io_stream_traps.h deleted file mode 100644 index e99d554e..00000000 --- a/aether/tele/traps/io_stream_traps.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_TRAPS_IO_STREAM_TRAPS_H_ -#define AETHER_TELE_TRAPS_IO_STREAM_TRAPS_H_ - -#include -#include -#include -#include -#include - -#include "aether/tele/itrap.h" - -namespace ae::tele { - -struct Metric { - std::uint32_t invocations_count; - std::uint32_t max_duration; - std::uint32_t sum_duration; - std::uint32_t min_duration; -}; - -class IoStreamTrap final : public ITrap { - public: - class LogLineWriter final : public ILogLine { - public: - LogLineWriter(std::ostream& s, Tag const& tag); - - void InvokeTime(TimePoint time) override; - void WriteLevel(Level level) override; - void WriteModule(Module const& module) override; - void Location(std::string_view file, std::uint32_t line) override; - void TagName(std::string_view name) override; - void Blob(std::span) override; - - private: - std::ostream& stream_; - }; - - explicit IoStreamTrap(std::ostream& stream); - ~IoStreamTrap() override; - - void AddInvoke(Tag const& tag, std::uint32_t count) override; - void AddInvokeDuration(Tag const& tag, Duration duration) override; - - void LogLine(Tag const& tag, ILogCollector& log_collector) override; - - void WriteEnvData(EnvData const& env_data) override; - - std::unordered_map const& metrics() const { - return metrics_; - } - - private: - std::mutex sync_lock_; - std::ostream& stream_; - std::unordered_map metrics_; -}; - -} // namespace ae::tele - -#endif // AETHER_TELE_TRAPS_IO_STREAM_TRAPS_H_ diff --git a/aether/tele/traps/proxy_trap.h b/aether/tele/traps/proxy_trap.h deleted file mode 100644 index 6d32a4e0..00000000 --- a/aether/tele/traps/proxy_trap.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_TRAPS_PROXY_TRAP_H_ -#define AETHER_TELE_TRAPS_PROXY_TRAP_H_ - -#include - -#include "aether/tele/itrap.h" - -namespace ae::tele { -template -class ProxyTrap final : public ITrap { - static_assert(std::is_base_of_v && - std::is_base_of_v, - "TrapFirst and TrapSecond must be derived from ITrap"); - - public: - ProxyTrap(std::shared_ptr trap1, std::shared_ptr trap2) - : first{std::move(trap1)}, second{std::move(trap2)} {} - - void AddInvoke(Tag const& tag, std::uint32_t count) override { - first->AddInvoke(tag, count); - second->AddInvoke(tag, count); - } - - void AddInvokeDuration(Tag const& tag, Duration duration) override { - first->AddInvokeDuration(tag, duration); - second->AddInvokeDuration(tag, duration); - } - - void LogLine(Tag const& tag, ILogCollector& log_collector) override { - first->LogLine(tag, log_collector); - second->LogLine(tag, log_collector); - } - - void WriteEnvData(EnvData const& env_data) override { - first->WriteEnvData(env_data); - second->WriteEnvData(env_data); - } - - std::shared_ptr first; - std::shared_ptr second; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_TRAPS_PROXY_TRAP_H_ diff --git a/aether/tele/traps/statistics_trap.cpp b/aether/tele/traps/statistics_trap.cpp deleted file mode 100644 index 26b97bdb..00000000 --- a/aether/tele/traps/statistics_trap.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#define AETHER_TELE_TELE_H_ - -#include "aether/tele/traps/statistics_trap.h" - -#include -#include -#include -#include - -namespace ae::tele { - -// print any integral to LogStorage -template - requires(std::is_integral_v) -ILogStorage& operator<<(ILogStorage& out, T v) { - out.Write(reinterpret_cast(&v), sizeof(T)); - return out; -} - -template -concept IndexSerializable = requires(ILogStorage& log_storage, T const t) { - { t.Serialize(log_storage) }; -}; - -template -concept IndexBuffSerializable = requires(std::uint8_t* buf, T const t) { - { t.Serialize(buf) } -> std::same_as; -}; - -template - requires(IndexSerializable || IndexBuffSerializable) -void WriteIndex(ILogStorage& log_storage, T const& v) { - if constexpr (IndexSerializable) { - v.Serialize(log_storage); - } else { - std::array buff; - auto s = v.Serialize(buff.data()); - log_storage.Write(buff.data(), s); - } -} - -StatisticsTrapBasic::LogLineWriter::LogLineWriter(Tag const& tag, - ILogStorage& log_storage) - : log_storage_{log_storage} { - auto tag_index = MetricsStore::PackedIndex{tag.index()}; - WriteIndex(log_storage_, tag_index); -} - -void StatisticsTrapBasic::LogLineWriter::InvokeTime(TimePoint time) { - auto epoch_ms = static_cast( - std::chrono::duration_cast( - time.time_since_epoch()) - .count()); - log_storage_ << epoch_ms; -} -void StatisticsTrapBasic::LogLineWriter::WriteLevel(Level level) { - log_storage_ << level.value_; -} -void StatisticsTrapBasic::LogLineWriter::WriteModule(Module const& module) { - log_storage_ << module.id; -} -void StatisticsTrapBasic::LogLineWriter::Location(std::string_view file, - std::uint32_t line) { - log_storage_.Write(reinterpret_cast(file.data()), - file.size()); - log_storage_ << line; -} -void StatisticsTrapBasic::LogLineWriter::TagName(std::string_view name) { - log_storage_.Write(reinterpret_cast(name.data()), - name.size()); -} -void StatisticsTrapBasic::LogLineWriter::Blob( - std::span blob) { - if (blob.empty()) { - return; - } - log_storage_.Write(blob.data(), blob.size()); -} - -StatisticsTrapBasic::StatisticsTrapBasic() = default; -StatisticsTrapBasic::~StatisticsTrapBasic() = default; - -void StatisticsTrapBasic::AddInvoke(Tag const& tag, std::uint32_t count) { - auto lock = std::scoped_lock(sync_lock_); - metrics_store_.metrics[tag.index()].invocations_count += count; -} - -void StatisticsTrapBasic::AddInvokeDuration(Tag const& tag, Duration duration) { - auto lock = std::scoped_lock(sync_lock_); - auto& metr = metrics_store_.metrics[tag.index()]; - - metr.sum_duration += static_cast(duration.count()); - metr.max_duration = std::max(static_cast(metr.max_duration), - static_cast(duration.count())); - - if (metr.min_duration == 0) { - metr.min_duration = static_cast(duration.count()); - } else { - metr.min_duration = std::min(static_cast(metr.min_duration), - static_cast(duration.count())); - } -} - -void StatisticsTrapBasic::WriteEnvData(EnvData const& env_data) { - env_store_.platform = env_data.platform_type; - env_store_.compiler = env_data.compiler; - env_store_.compiler_version = env_data.compiler_version; - env_store_.library_version = env_data.library_version; - env_store_.cpu_arch = env_data.cpu_arch; - env_store_.endianness = static_cast(env_data.endianness); - env_store_.utm_id = env_data.utm_id; - for (auto const& opt : env_data.compile_options) { - env_store_.compile_options.emplace_back(EnvStore::PackedIndex{opt.index}, - std::string{opt.value}); - } -} - -void StatisticsTrapBasic::MergeStatistics(StatisticsTrapBasic const& newer) { - // just steal env_store_ - env_store_ = newer.env_store_; - - // merge metrics - for (auto const& [index, metric] : newer.metrics_store_.metrics) { - auto it = metrics_store_.metrics.find(index); - if (it == std::end(metrics_store_.metrics)) { - metrics_store_.metrics[index] = metric; - continue; - } - it->second.invocations_count += metric.invocations_count; - it->second.max_duration = - std::max(it->second.max_duration, metric.max_duration); - it->second.min_duration = - std::min(it->second.min_duration, metric.min_duration); - it->second.sum_duration += metric.sum_duration; - } -} - -EnvStore const& StatisticsTrapBasic::env_store() const { return env_store_; } -MetricsStore const& StatisticsTrapBasic::metrics_store() const { - return metrics_store_; -} - -} // namespace ae::tele diff --git a/aether/tele/traps/statistics_trap.h b/aether/tele/traps/statistics_trap.h deleted file mode 100644 index ef9b847c..00000000 --- a/aether/tele/traps/statistics_trap.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_TELE_TRAPS_STATISTICS_TRAP_H_ -#define AETHER_TELE_TRAPS_STATISTICS_TRAP_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aether-miscpp/reflect/reflect.h" -#include "numeric/tiered_int.h" - -#include "aether/tele/itrap.h" - -namespace ae::tele { -/** - * \brief Map of telemetry metrics. - */ -struct MetricsStore { - using PackedIndex = TieredInt; - using PackedCount = TieredInt; - struct Metric { - PackedCount invocations_count; - std::uint32_t max_duration; - std::uint32_t sum_duration; - std::uint32_t min_duration; - - AE_REFLECT_MEMBERS(invocations_count, max_duration, sum_duration, - min_duration) - }; - - using MetricsMap = std::map; - - AE_REFLECT_MEMBERS(metrics) - - MetricsMap metrics; -}; - -/** - * \brief Stores environment information related to the compilation and runtime - * of the application. - */ -struct EnvStore { - using PackedIndex = TieredInt; - - std::string library_version; - std::string platform; - std::string compiler; - std::string compiler_version; - std::string cpu_arch; - std::uint8_t endianness; - std::uint32_t utm_id; - std::vector> compile_options; - - AE_REFLECT_MEMBERS(library_version, platform, compiler, compiler_version, - cpu_arch, endianness, utm_id, compile_options) -}; - -class ILogStorage { - protected: - ~ILogStorage() = default; - - public: - virtual void Write(std::uint8_t const* data, std::size_t size) = 0; -}; - -// LogStorage with circular buffer and fixed capacity -template -struct LogStorage final : public ILogStorage { - void Write(std::uint8_t const* data, std::size_t count) override { - count = std::min(count, LogCapacity - 1); - - if (count > LogCapacity - 1 - size()) { - auto overwrite = count - (LogCapacity - 1 - size()); - start = (start + overwrite) % LogCapacity; - } - - while (count > 0) { - auto n = (LogCapacity - pos) > count ? count : LogCapacity - pos; - std::memcpy(buffer.data() + pos, data, n); - pos = (pos + n) % LogCapacity; - data += n; - count -= n; - } - } - - std::size_t size() const { - if (pos >= start) { - return pos - start; - } - return LogCapacity - start + pos; - } - - // read from stream - template - friend TStream& operator>>(TStream& in, LogStorage& v) { - std::uint32_t size; // NOLINT(*init-variables) - in >> size; - assert(size < LogCapacity && "Saved buffer bigger than capacity"); - v.start = 0; - v.pos = static_cast(size); - in.read(v.buffer.data(), static_cast(size)); - - return in; - } - - // write to stream - template - friend TStream& operator<<(TStream& out, LogStorage const& v) { - auto size = v.size(); - out << static_cast(size); - auto s = v.start; - while (size > 0) { - auto to_write = (LogCapacity - s) > size ? size : LogCapacity - s; - out.write(v.buffer.data() + s, to_write); - s = (s + to_write) % LogCapacity; - size = size - to_write; - } - - return out; - } - - std::size_t start{}; - std::size_t pos{}; - std::array buffer; -}; - -class StatisticsTrapBasic : public ITrap { - public: - class LogLineWriter final : public ILogLine { - public: - LogLineWriter(Tag const& tag, ILogStorage& log_storage); - - void InvokeTime(TimePoint time) override; - void WriteLevel(Level level) override; - void WriteModule(Module const& module) override; - void Location(std::string_view file, std::uint32_t line) override; - void TagName(std::string_view name) override; - void Blob(std::span blob) override; - - private: - ILogStorage& log_storage_; - }; - - StatisticsTrapBasic(); - ~StatisticsTrapBasic() override; - - void AddInvoke(Tag const& tag, std::uint32_t count) override; - void AddInvokeDuration(Tag const& tag, Duration duration) override; - // LogLine implemented not here - - void WriteEnvData(EnvData const& env_data) override; - - void MergeStatistics(StatisticsTrapBasic const& newer); - - EnvStore const& env_store() const; - MetricsStore const& metrics_store() const; - - AE_REFLECT_MEMBERS(metrics_store_, env_store_) - - protected: - std::mutex sync_lock_; - MetricsStore metrics_store_{}; - EnvStore env_store_{}; -}; - -/** - * \brief Access to statistics storage through telemetry trap - */ -template -class StatisticsTrap final : public StatisticsTrapBasic { - public: - StatisticsTrap() = default; - - void LogLine(Tag const& tag, ILogCollector& log_collector) override { - auto lock = std::scoped_lock{sync_lock_}; - auto log_writer = StatisticsTrapBasic ::LogLineWriter{tag, log_storage_}; - log_collector.WriteLine(log_writer); - } - - /** - * \brief Merge newer statistics storage into this - */ - void MergeStatistics(StatisticsTrap const& newer) { - StatisticsTrapBasic::MergeStatistics(newer); - // write newer logs on top of current - auto size = newer.log_storage_.size(); - auto s = newer.log_storage_.start; - while (size > 0) { - auto to_write = (LogCapacity - s) > size ? size : LogCapacity - s; - log_storage_.Write(newer.log_storage_.buffer.data() + s, to_write); - s = (s + to_write) % LogCapacity; - size = size - to_write; - } - } - - LogStorage const& log_storage() const { return log_storage_; } - - AE_REFLECT(AE_REF_BASE(StatisticsTrapBasic), AE_MMBRS(log_storage_)) - - private: - LogStorage log_storage_; -}; -} // namespace ae::tele - -#endif // AETHER_TELE_TRAPS_STATISTICS_TRAP_H_ diff --git a/aether/tele_compile_options.h b/aether/tele_compile_options.h index 009e4415..ffcc29ca 100644 --- a/aether/tele_compile_options.h +++ b/aether/tele_compile_options.h @@ -21,7 +21,7 @@ #include #include -#include "aether/tele/compile_option.h" +#include "aether-tele/compile_option.h" #include "aether/common.h" #include "aether/config.h" diff --git a/aether/tele_statistics.h b/aether/tele_statistics.h index 1ebb9f62..50db1e07 100644 --- a/aether/tele_statistics.h +++ b/aether/tele_statistics.h @@ -19,7 +19,7 @@ #include -#include "aether/tele/traps/statistics_trap.h" +#include "aether-tele/traps/statistics_trap.h" #include "aether/config.h" #include "aether/obj/obj.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f9307dc5..75f91278 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,7 +31,6 @@ add_subdirectory(inline_tests) generate_inline_tests(${CMAKE_CURRENT_LIST_DIR}/../aether aether) #tests -add_subdirectory(test-tele) add_subdirectory(test-types) add_subdirectory(test-object-system) add_subdirectory(test-api-protocol) diff --git a/tests/test-object-system/CMakeLists.txt b/tests/test-object-system/CMakeLists.txt index 1c184126..f1d24cc3 100644 --- a/tests/test-object-system/CMakeLists.txt +++ b/tests/test-object-system/CMakeLists.txt @@ -14,11 +14,6 @@ cmake_minimum_required( VERSION 3.16 ) -list(APPEND other_aether_srcs - ${ROOT_DIR}/aether/tele/traps/io_stream_traps.cpp - ${ROOT_DIR}/aether/tele/traps/statistics_trap.cpp -) - list(APPEND test_obj_srcs ${ROOT_DIR}/aether/ptr/ptr.cpp ${ROOT_DIR}/aether/ptr/ptr_view.cpp @@ -52,7 +47,7 @@ if(NOT CM_PLATFORM) # for aether target_include_directories(${PROJECT_NAME} PRIVATE ${ROOT_DIR}) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) - target_link_libraries(${PROJECT_NAME} PRIVATE unity etl numeric aether::miscpp) + target_link_libraries(${PROJECT_NAME} PRIVATE unity etl numeric aether::miscpp aether-tele) target_compile_definitions(${PROJECT_NAME} PRIVATE "AE_DISTILLATION=1") target_compile_definitions(${PROJECT_NAME} PRIVATE "AE_PROJECT_VERSION=\"0.0.0\"") diff --git a/tests/test-tele/CMakeLists.txt b/tests/test-tele/CMakeLists.txt deleted file mode 100644 index 188459de..00000000 --- a/tests/test-tele/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2024 Aethernet Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required( VERSION 3.16 ) - -list(APPEND test_tele_srcs - ${ROOT_DIR}/aether/tele/traps/io_stream_traps.cpp - ${ROOT_DIR}/aether/tele/traps/statistics_trap.cpp - ${ROOT_DIR}/aether/ptr/ptr.cpp - ${ROOT_DIR}/aether/ptr/ptr_view.cpp - ${ROOT_DIR}/aether/ptr/ref_tree.cpp -) - -list(APPEND test_srcs - test-tele.cpp -) - -if(NOT CM_PLATFORM) - project(test-tele LANGUAGES CXX) - - add_executable(${PROJECT_NAME}) - target_sources(${PROJECT_NAME} PRIVATE ${test_tele_srcs} ${test_srcs}) - # for aether - target_include_directories(${PROJECT_NAME} PRIVATE ${ROOT_DIR}) - target_link_libraries(${PROJECT_NAME} PRIVATE unity numeric aether::miscpp) - target_compile_definitions(${PROJECT_NAME} PRIVATE AE_PROJECT_VERSION="0.0.0") - - add_test(NAME ${PROJECT_NAME} COMMAND $) - - if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - target_compile_options(${PROJECT_NAME} PUBLIC /Zc:preprocessor) - endif() -else() - message(WARNING "Not implemented for ${CM_PLATFORM}") -endif() diff --git a/tests/test-tele/test-tele.cpp b/tests/test-tele/test-tele.cpp deleted file mode 100644 index 376ea54b..00000000 --- a/tests/test-tele/test-tele.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright 2024 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aether-miscpp/meta/arg_at.h" - -#include "aether/config.h" - -// force to enable telemetry for this test -#if defined AE_TELE_ENABLED -# undef AE_TELE_ENABLED -# define AE_TELE_ENABLED 1 -#endif - -#if defined AE_TELE_METRICS_MODULES -# undef AE_TELE_METRICS_MODULES -# define AE_TELE_METRICS_MODULES AE_ALL -#endif - -#if defined AE_TELE_METRICS_DURATION -# undef AE_TELE_METRICS_DURATION -# define AE_TELE_METRICS_DURATION AE_ALL -#endif - -#define AETHER_TELE_TELE_H_ - -#include "aether/tele/collectors.h" -#include "aether/tele/defines.h" -#include "aether/tele/env_collectors.h" -#include "aether/tele/modules.h" -#include "aether/tele/sink.h" -#include "aether/tele/tags.h" - -#include "aether/tele/configs/all_enabled.h" - -#include "aether/tele/traps/io_stream_traps.h" -#include "aether/tele/traps/proxy_trap.h" -#include "aether/tele/traps/statistics_trap.h" - -using SinkType = ae::tele::TeleSink; - -#define TELE_SINK SinkType -static std::shared_ptr trap; - -void setUp() { - trap = std::make_shared(std::cout); - - SinkType::Instance().SetTrap(trap); -} - -void tearDown() {} - -AE_TELE_MODULE(TestObj, 12, 1, 20); - -AE_TAG(Zero, TestObj) -AE_TAG(One, TestObj) -AE_TAG(Two, TestObj) -AE_TAG(Three, TestObj) -// duplicated! -AE_TAG(Four, TestObj) -// duplicated! - -AE_TAG(Test1, TestObj) -AE_TAG(Test2, TestObj) -AE_TAG(Test3, TestObj) - -namespace ae::tele::test_tele { -namespace { - -void AssertTimestampShape(std::string const& timestamp) { - TEST_ASSERT_EQUAL(15U, timestamp.size()); - TEST_ASSERT_EQUAL(':', timestamp[2]); - TEST_ASSERT_EQUAL(':', timestamp[5]); - TEST_ASSERT_EQUAL('.', timestamp[8]); - for (auto i = std::size_t{}; i < timestamp.size(); ++i) { - if ((i == 2) || (i == 5) || (i == 8)) { - continue; - } - TEST_ASSERT(std::isdigit(static_cast(timestamp[i])) != 0); - } -} - -} // namespace - -void test_Register() { - TEST_ASSERT_EQUAL(1, One.offset); - TEST_ASSERT_EQUAL(2, Two.offset); - TEST_ASSERT_EQUAL(3, Three.offset); - TEST_ASSERT_EQUAL(4, Four.offset); -} - -void test_SimpleTeleWithDuration() { - { - AE_TELE_DEBUG(Test1); - AE_TELE_DEBUG(Test1, "format {}", 12); - AE_TELE_INFO(Test2, "format {}", 24); - AE_TELE_INFO(Test3, "format {}", 48); - // must not compile - // AE_TELE_INFO(Not_registered, "format {}", 96); - } - auto const& metrics = trap->metrics().at(Test1.offset + TestObj.index_start); - - TEST_ASSERT_EQUAL(2, metrics.invocations_count); -} - -namespace tele_configuration { -struct TeleTrap final : public ITrap { - struct MetricData { - std::uint32_t count_{}; - std::uint32_t duration_{}; - }; - - class LogLineWriter final : public ILogLine { - public: - explicit LogLineWriter(std::vector& line) : log_line{line} {} - /** - * \brief Telemetry invoke time. - */ - void InvokeTime(TimePoint time) override { - log_line.emplace_back(Format("{:time}", time)); - }; - /** - * \brief Telemetry tag level - */ - void WriteLevel(Level level) override { - log_line.emplace_back(level.Text()); - }; - /** - * \brief Tag module - */ - void WriteModule(Module const& module) override { - log_line.emplace_back(module.name); - }; - /** - * \brief Tag location - */ - void Location(std::string_view file, std::uint32_t line) override { - log_line.emplace_back(Format("{file}:{line}", file, line)); - }; - /** - * \brief Tag name - */ - void TagName(std::string_view name) override { - log_line.emplace_back(name); - }; - /** - * \brief Get stream to write telemetry blob data. - */ - void Blob(std::span blob) override { - log_line.emplace_back(reinterpret_cast(blob.data()), - blob.size()); - }; - std::vector& log_line; - }; - - void AddInvoke(Tag const& tag, std::uint32_t count) override { - metric_data_[tag.index()].count_ += count; - } - void AddInvokeDuration(Tag const& tag, Duration duration) override { - metric_data_[tag.index()].duration_ += - static_cast(duration.count()); - } - void LogLine(Tag const& tag, ILogCollector& log_collector) override { - auto& line = log_lines_.emplace_back(); - line.emplace_back(std::to_string(tag.index())); - auto writer = LogLineWriter{line}; - log_collector.WriteLine(writer); - } - - void WriteEnvData(EnvData const& /*env_data*/) override {} - - std::list> log_lines_; - std::map metric_data_; -}; - -template -struct ConfigProvider { - template - static consteval auto GetTeleConfig() { - return TeleConfig{ - .count_metrics = Count, - .time_metrics = Time, - .logs_enabled = LogsEnabled, - .start_time_logs = StartTime, - .level_module_logs = LevelModule, - .location_logs = Location, - .name_logs = TagName, - .blob_logs = Blob, - }; - }; - - static consteval auto GetEnvConfig() { - return EnvConfig{.static_info = true, .runtime_info = true}; - } -}; -} // namespace tele_configuration - -void test_TeleConfigurations() { - constexpr auto TestTag = Tag{11, TestObj, "Test"}; - { - // all enabled - using Sink = TeleSink>; - auto tele_trap = std::make_shared(); - - Sink::Instance().SetTrap(tele_trap); - { - auto t = - Tele()>{ - Sink::Instance(), - TestTag, - Level{Level::kDebug}, - "test-tele.cpp", - 8, - "message {}", - 12, - }; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_.size()); - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_[12].count_); - TEST_ASSERT_GREATER_THAN(1, tele_trap->metric_data_[12].duration_); - - TEST_ASSERT_EQUAL(1, tele_trap->log_lines_.size()); - auto& log_line = tele_trap->log_lines_.front(); - TEST_ASSERT_EQUAL(7, log_line.size()); - TEST_ASSERT_EQUAL_STRING("12", log_line[0].c_str()); - AssertTimestampShape(log_line[1]); - TEST_ASSERT_EQUAL_STRING("kDebug", log_line[2].c_str()); - TEST_ASSERT_EQUAL_STRING("TestObj", log_line[3].c_str()); - TEST_ASSERT_EQUAL_STRING("test-tele.cpp:8", log_line[4].c_str()); - TEST_ASSERT_EQUAL_STRING("Test", log_line[5].c_str()); - TEST_ASSERT_EQUAL_STRING("message 12", log_line[6].c_str()); - } - - { - // only metrics - using Sink = TeleSink>; - auto tele_trap = std::make_shared(); - - Sink::Instance().SetTrap(tele_trap); - { - auto t = - Tele()>{ - Sink::Instance(), - TestTag, - Level{Level::kDebug}, - "test-tele.cpp", - 8, - "message {}", - 12, - }; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_.size()); - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_[12].count_); - TEST_ASSERT_GREATER_THAN(1, tele_trap->metric_data_[12].duration_); - - TEST_ASSERT(tele_trap->log_lines_.empty()); - } - { - // only count - using Sink = TeleSink>; - auto tele_trap = std::make_shared(); - Sink::Instance().SetTrap(tele_trap); - { - auto t = - Tele()>{ - Sink::Instance(), - TestTag, - Level{Level::kDebug}, - "test-tele.cpp", - 8, - "message {}", - 12, - }; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_.size()); - TEST_ASSERT_EQUAL(1, tele_trap->metric_data_[12].count_); - TEST_ASSERT_EQUAL(0, tele_trap->metric_data_[12].duration_); - - TEST_ASSERT(tele_trap->log_lines_.empty()); - } - { - // nothing - using Sink = TeleSink>; - auto tele_trap = std::make_shared(); - - Sink::Instance().SetTrap(tele_trap); - { - auto t = - Tele()>{ - Sink::Instance(), - TestTag, - Level{Level::kDebug}, - "test-tele.cpp", - 8, - "message {}", - 12, - }; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - TEST_ASSERT(tele_trap->metric_data_.empty()); - TEST_ASSERT(tele_trap->log_lines_.empty()); - } - { - // print only index log level, module and text - using Sink = - TeleSink>; - auto tele_trap = std::make_shared(); - - Sink::Instance().SetTrap(tele_trap); - { - auto t = - Tele()>{ - Sink::Instance(), - TestTag, - Level{Level::kDebug}, - "test-tele.cpp", - 8, - "message {}", - 12, - }; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - TEST_ASSERT(tele_trap->metric_data_.empty()); - - TEST_ASSERT_EQUAL(1, tele_trap->log_lines_.size()); - auto& log_line = tele_trap->log_lines_.front(); - TEST_ASSERT_EQUAL(4, log_line.size()); - TEST_ASSERT_EQUAL_STRING("12", log_line[0].c_str()); - TEST_ASSERT_EQUAL_STRING("kDebug", log_line[1].c_str()); - TEST_ASSERT_EQUAL_STRING("TestObj", log_line[2].c_str()); - TEST_ASSERT_EQUAL_STRING("Test", log_line[3].c_str()); - } -} - -void test_TeleProxyTrap() { - using ProxyTeleTrap = - ProxyTrap; - - auto first_trap = std::make_shared(); - auto second_trap = std::make_shared(); - auto proxy_tele_trap = - std::make_shared(first_trap, second_trap); - - SinkType::Instance().SetTrap(proxy_tele_trap); - - { - AE_TELE_DEBUG(Test1); - AE_TELE_DEBUG(Test1, "format {}", 12); - AE_TELE_INFO(Test2, "format {}", 24); - AE_TELE_INFO(Test2, "format {}", 48); - } - - auto& metrics = first_trap->metric_data_[Test1.offset + TestObj.index_start]; - - TEST_ASSERT_EQUAL(2, metrics.count_); - - auto d = second_trap->metric_data_[Test1.offset + TestObj.index_start]; - TEST_ASSERT_EQUAL(metrics.count_, d.count_); -} - -void test_MergeStatisticsTrap() { - using Sink = - TeleSink>; -#undef TELE_SINK -#define TELE_SINK Sink - using Trap = StatisticsTrap<1024>; - auto statistics_trap1 = std::make_shared(); - - Sink::Instance().SetTrap(statistics_trap1); - { - AE_TELE_DEBUG(Test1); - AE_TELE_INFO(Test1); - AE_TELE_WARNING(Test1); - AE_TELE_ERROR(Test1); - AE_TELE_DEBUG(Test2); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - auto const& logs1 = statistics_trap1->log_storage(); - - auto statistics_trap2 = std::make_shared(); - statistics_trap2->MergeStatistics(*statistics_trap1); - - auto const& logs2 = statistics_trap2->log_storage(); - - TEST_ASSERT_EQUAL(logs1.size(), logs2.size()); - TEST_ASSERT_EQUAL_CHAR_ARRAY(logs1.buffer.data(), logs2.buffer.data(), - logs2.buffer.size()); - - auto const& metrics1 = statistics_trap1->metrics_store().metrics; - auto const& metrics2 = statistics_trap2->metrics_store().metrics; - - TEST_ASSERT_EQUAL(metrics1.size(), metrics2.size()); - auto mit1 = std::begin(metrics1); - auto mit2 = std::begin(metrics2); - for (; mit1 != std::end(metrics1); ++mit1, ++mit2) { - TEST_ASSERT_EQUAL(mit1->first, mit2->first); - TEST_ASSERT_EQUAL(mit1->second.invocations_count, - mit2->second.invocations_count); - TEST_ASSERT_EQUAL(mit1->second.max_duration, mit2->second.max_duration); - TEST_ASSERT_EQUAL(mit1->second.min_duration, mit2->second.min_duration); - TEST_ASSERT_EQUAL(mit1->second.sum_duration, mit2->second.sum_duration); - } - // switch to trap 2 - Sink::Instance().SetTrap(statistics_trap2); - { - AE_TELE_DEBUG(Test1); - AE_TELE_DEBUG(Test2); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - // new logs added - TEST_ASSERT_NOT_EQUAL(logs1.size(), logs2.size()); - // but no new metrics - TEST_ASSERT_EQUAL(metrics1.size(), metrics2.size()); - auto new_mit1 = std::begin(metrics1); - auto new_mit2 = std::begin(metrics2); - for (; new_mit1 != std::end(metrics1); ++new_mit1, ++new_mit2) { - TEST_ASSERT_EQUAL(new_mit1->first, new_mit2->first); - TEST_ASSERT_NOT_EQUAL(new_mit1->second.invocations_count, - new_mit2->second.invocations_count); - TEST_ASSERT_NOT_EQUAL(new_mit1->second.sum_duration, - new_mit2->second.sum_duration); - } - -#undef TELE_SINK -#define TELE_SINK SinkType -} - -void test_StatisticsRotation() { - using Trap = ae::tele::StatisticsTrap<1024>; - - auto ts = std::make_shared(); - SinkType::Instance().SetTrap(ts); - // check if ts is empty - TEST_ASSERT_EQUAL(0, ts->log_storage().size()); - // add some logs - { - AE_TELE_DEBUG(Test1, "12"); - } - // something was added - TEST_ASSERT_GREATER_THAN(0, ts->log_storage().size()); - - // write too many - std::array garbage{}; - { - AE_TELE_DEBUG(Test1, "13 {}", garbage); - } - TEST_ASSERT_EQUAL(1023, ts->log_storage().size()); -} - -void test_SaveLoadTeleStatistics() { - using Trap = ae::tele::StatisticsTrap<1024>; - - auto ts_0 = std::make_shared(); - auto ts_1 = std::make_shared(); - - // first set ts_0 and write some logs - SinkType::Instance().SetTrap(ts_0); - { - AE_TELE_DEBUG(Test1, "12"); - } - auto size_before = ts_0->log_storage().size(); - - // merge 1 and 0 - ts_1->MergeStatistics(*ts_0); - auto size_after_merge = ts_1->log_storage().size(); - TEST_ASSERT_EQUAL(size_before, size_after_merge); - - auto const& metrics1 = ts_0->metrics_store().metrics; - auto const& metrics2 = ts_1->metrics_store().metrics; - TEST_ASSERT_EQUAL(metrics1.size(), metrics2.size()); - - auto log_index = - ae::tele::MetricsStore::PackedIndex{TestObj.index_start + Test1.offset}; - // simple check with _AE_MODULE_CONFIG leads here to AST broken error for - // cppcheck - if constexpr (TELE_SINK::GetTeleConfig() - .time_metrics) { - TEST_ASSERT_EQUAL(metrics1.at(log_index).sum_duration, - metrics2.at(log_index).sum_duration); - } - - if constexpr (TELE_SINK::GetTeleConfig() - .count_metrics) { - TEST_ASSERT_EQUAL(metrics1.at(log_index).invocations_count, - metrics2.at(log_index).invocations_count); - } - - SinkType::Instance().SetTrap(ts_1); - { - AE_TELE_DEBUG(Test1, "13"); - } - - // check if new log added - TEST_ASSERT_GREATER_THAN(size_before, ts_1->log_storage().size()); -} - -template -struct LambdaLogCollector final : public ILogCollector { - explicit LambdaLogCollector(WriteFn&& wf) : write_fn{std::move(wf)} {} - void WriteLine(ILogLine& log_line) override { write_fn(log_line); } - WriteFn write_fn; -}; - -void test_IoStreamTrapFullOutput() { - auto stream = std::ostringstream{}; - auto trap = IoStreamTrap{stream}; - auto const fixed_time = - TimePoint{std::chrono::hours{3} + std::chrono::minutes{4} + - std::chrono::seconds{5} + std::chrono::microseconds{123456}}; - auto const tag = Tag{11, TestObj, "Test"}; - - auto log_collector = LambdaLogCollector{[&](ILogLine& log_line) { - log_line.InvokeTime(fixed_time); - log_line.WriteLevel(Level{Level::kDebug}); - log_line.WriteModule(TestObj); - log_line.Location("src/test-tele.cpp", 42); - log_line.TagName(tag.name); - log_line.Blob( - std::span{reinterpret_cast("message 12"), 10}); - }}; - - trap.LogLine(tag, log_collector); - - auto const output = stream.str(); - TEST_ASSERT_EQUAL_STRING( - " 12:[03:04:05.123456]:kDebug:TestObj:test-tele.cpp:42:Test:message " - "12\n", - output.c_str()); -} - -void test_IoStreamTrapLocationWithoutSeparatorUsesUnknownFile() { - auto stream = std::ostringstream{}; - auto trap = IoStreamTrap{stream}; - auto const tag = Tag{11, TestObj, "Test"}; - - auto log_collector = LambdaLogCollector{ - [&](ILogLine& log_line) { log_line.Location("test-tele.cpp", 42); }}; - - trap.LogLine(tag, log_collector); - - auto const output = stream.str(); - TEST_ASSERT_EQUAL_STRING(" 12:UNKNOWN FILE:42\n", output.c_str()); -} -void test_EnvTele() { AE_TELE_ENV(); } - -} // namespace ae::tele::test_tele - -int main() { - UNITY_BEGIN(); - - RUN_TEST(ae::tele::test_tele::test_Register); - RUN_TEST(ae::tele::test_tele::test_SimpleTeleWithDuration); - RUN_TEST(ae::tele::test_tele::test_TeleConfigurations); - RUN_TEST(ae::tele::test_tele::test_TeleProxyTrap); - RUN_TEST(ae::tele::test_tele::test_MergeStatisticsTrap); - RUN_TEST(ae::tele::test_tele::test_StatisticsRotation); - RUN_TEST(ae::tele::test_tele::test_SaveLoadTeleStatistics); - RUN_TEST(ae::tele::test_tele::test_IoStreamTrapFullOutput); - RUN_TEST(ae::tele::test_tele:: - test_IoStreamTrapLocationWithoutSeparatorUsesUnknownFile); - RUN_TEST(ae::tele::test_tele::test_EnvTele); - RUN_TEST(ae::tele::test_tele::test_EnvTele); - RUN_TEST(ae::tele::test_tele::test_EnvTele); - - return UNITY_END(); -}