Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2913a9f200
|
||
|
|
caaf34c9ff
|
||
|
|
c2f23156ac
|
||
|
|
0f2327507f
|
||
|
|
760b7f0a0d
|
||
|
|
aeec64c539 | ||
|
|
e2bce64102 | ||
|
|
b6a2ac3631
|
||
|
|
81647be127
|
||
|
|
e6bda14097 | ||
|
|
f9f415f5d3
|
||
|
|
c6f13121a1
|
||
|
|
9086c8d15e
|
||
|
|
fefcb4fbfa
|
||
|
|
22c850c025
|
||
|
|
03db9b6f89 | ||
|
|
afde841966 | ||
|
|
1731d749ab | ||
|
|
241e843364 | ||
|
|
ab57dd545a | ||
|
|
431e0fce84 | ||
|
|
bd50f5a760 | ||
|
|
5f245adf59 | ||
|
|
1a78ac8976 | ||
|
|
efc8dc0567 | ||
|
|
767141e956 | ||
|
|
2e8baba5fb | ||
|
|
d3ed64202f | ||
|
|
e8d8210532 | ||
|
|
0129f1822b | ||
|
|
48afbdd4d7 | ||
|
|
a7becd6f0b | ||
|
|
8ed9fd5096 | ||
|
|
060ee0d7d8
|
||
|
|
4c82d5b4f0 | ||
|
|
671fd10d45
|
||
|
|
d1a04a385f | ||
|
|
bfe8892f71
|
||
|
|
680f76e3a3 | ||
|
|
e0c81bf68d
|
||
|
|
e071cca97e | ||
|
|
187a56825a | ||
|
|
22fae54689 | ||
|
|
90be19f913 | ||
|
|
2db99e17ea | ||
|
|
d85789c16f | ||
|
|
d7a186f78b | ||
|
|
4ba088fb81 | ||
|
|
5328b07af3 | ||
|
|
7084430141 | ||
|
|
746a3642d7 | ||
|
|
eef914d881 | ||
|
|
389e366f5e | ||
|
|
0ee8782881 | ||
|
|
0f2ec03390 | ||
|
|
1374795e68 | ||
|
|
c3640b90d7 | ||
|
|
e8f0f2b88e | ||
|
|
33051ae997 | ||
|
|
6c261c7458 | ||
|
|
68d25205d1 | ||
|
|
32720776f2 | ||
|
|
3f8d113f61 | ||
|
|
0e556e09e4 | ||
|
|
5a44c5d1a8 | ||
|
|
6d283a2ca4 | ||
|
|
77d8d90ebb | ||
|
|
212fc98365 | ||
|
|
77328af459 | ||
|
|
6dc7c12613 | ||
|
|
d29af04c03 | ||
|
|
c50afb87ab |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
Acceptance: a fresh protected-branch build must publish through the scheduled trusted publisher and resolve from an empty Maven cache.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Organization-scoped CI qualification. Workflow implementation lives in platform-ci; enrollment lives in ci-policy.
|
||||||
|
|
||||||
|
Shared CI tooling visibility approved and public; qualify public consumer access.
|
||||||
+10
-53
@@ -1,57 +1,14 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
|
setup: true
|
||||||
orbs:
|
orbs:
|
||||||
qqq-orb: kingsrook/qqq-orb@0.5.0
|
qqq-orb: kingsrook/qqq-orb@0.8
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
|
setup:
|
||||||
test_only:
|
|
||||||
jobs:
|
jobs:
|
||||||
- qqq-orb/mvn_test_only:
|
- qqq-orb/generate_pipeline:
|
||||||
context: [ qqq-maven-registry-credentials ]
|
orb_version: '0.8'
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore: /(develop|main|release/.*|hotfix/.*|integration.*)/
|
ignore: automation/qbit-rc-pending
|
||||||
tags:
|
tags:
|
||||||
only: []
|
only: /^v\d+\.\d+\.\d+$/
|
||||||
|
|
||||||
publish_snapshot:
|
|
||||||
jobs:
|
|
||||||
- qqq-orb/mvn_publish:
|
|
||||||
context: [ qqq-maven-registry-credentials ]
|
|
||||||
branch_type: snapshot
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
publish_release_candidate:
|
|
||||||
jobs:
|
|
||||||
- qqq-orb/mvn_publish:
|
|
||||||
context: [ qqq-maven-registry-credentials ]
|
|
||||||
branch_type: release_candidate
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- /release\/.*/
|
|
||||||
|
|
||||||
publish_release:
|
|
||||||
jobs:
|
|
||||||
- qqq-orb/mvn_publish:
|
|
||||||
context: [ qqq-maven-registry-credentials ]
|
|
||||||
branch_type: release
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only: [ main ]
|
|
||||||
tags:
|
|
||||||
only: [ /v.*/ ]
|
|
||||||
|
|
||||||
publish_hotfix_release:
|
|
||||||
jobs:
|
|
||||||
- qqq-orb/mvn_publish:
|
|
||||||
context: [ qqq-maven-registry-credentials ]
|
|
||||||
branch_type: hotfix
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- /hotfix\/.*/
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
name: build
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
jobs:
|
||||||
|
maven:
|
||||||
|
uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/maven.yaml@v1
|
||||||
|
secrets: inherit
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
* @KofTwentyTwo
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: CodeQL
|
||||||
|
'on':
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
- release/**
|
||||||
|
- hotfix/**
|
||||||
|
pull_request: {}
|
||||||
|
schedule:
|
||||||
|
- cron: 41 16 * * 0
|
||||||
|
workflow_dispatch: {}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
security-events: write
|
||||||
|
packages: read
|
||||||
|
concurrency:
|
||||||
|
group: codeql-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
uses: QRun-IO/qqq-orb/.github/workflows/qbit-codeql.yml@c288a8864fe9054f68410e1d78f5863aea4c4d22
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
name: Release candidate
|
||||||
|
'on':
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
dry_run:
|
||||||
|
description: Plan a cut without changing release state
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
finalize:
|
||||||
|
description: Retry finalization of an existing cut; do not cut another RC
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
recover:
|
||||||
|
description: Recover the same published RC after a deployment timeout; never
|
||||||
|
reupload
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
circle_build:
|
||||||
|
description: Original Circle publisher build number (recovery only)
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
merge_sha:
|
||||||
|
description: Existing cut merge_sha (finalize retry only)
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
bump_sha:
|
||||||
|
description: Existing cut bump_sha (finalize retry only)
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
branch:
|
||||||
|
description: Existing cut branch (finalize retry only)
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
version:
|
||||||
|
description: Existing cut version (finalize retry only)
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
repository_dispatch:
|
||||||
|
types:
|
||||||
|
- qbit-rc-published
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
actions: read
|
||||||
|
checks: read
|
||||||
|
jobs:
|
||||||
|
release-rc:
|
||||||
|
if: github.event_name == 'workflow_dispatch' || github.event_name == 'repository_dispatch'
|
||||||
|
|| (github.event_name == 'pull_request' && github.event.pull_request.merged
|
||||||
|
== true && github.event.pull_request.base.ref == 'develop' && contains(github.event.pull_request.labels.*.name,
|
||||||
|
'release:rc'))
|
||||||
|
uses: QRun-IO/qqq-orb/.github/workflows/qbit-release-rc.yml@cc30f599e63c8e41629c99d23395bac1adb8bc44
|
||||||
|
with:
|
||||||
|
dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false
|
||||||
|
}}
|
||||||
|
finalize: ${{ github.event_name == 'repository_dispatch' || (github.event_name
|
||||||
|
== 'workflow_dispatch' && inputs.finalize) }}
|
||||||
|
recover: ${{ github.event_name == 'workflow_dispatch' && inputs.recover || false
|
||||||
|
}}
|
||||||
|
circle_build: ${{ github.event_name == 'workflow_dispatch' && inputs.circle_build
|
||||||
|
|| '' }}
|
||||||
|
merge_sha: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.merge_sha
|
||||||
|
|| inputs.merge_sha || '' }}
|
||||||
|
bump_sha: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.bump_sha
|
||||||
|
|| inputs.bump_sha || '' }}
|
||||||
|
branch: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch
|
||||||
|
|| inputs.branch || '' }}
|
||||||
|
version: ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.version
|
||||||
|
|| inputs.version || '' }}
|
||||||
|
secrets: inherit
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
profile: qbit
|
||||||
|
orb_version: '0.8'
|
||||||
|
default_branch: develop
|
||||||
|
java_version: '21'
|
||||||
|
browsers: true
|
||||||
|
api_checks: false
|
||||||
|
docs_only: false
|
||||||
|
release_on_main: false
|
||||||
|
release_tag_policy: stable
|
||||||
|
test_branch_policy: non-release
|
||||||
|
publish:
|
||||||
|
snapshot: true
|
||||||
|
release_candidate: true
|
||||||
|
release: true
|
||||||
|
asciidoc: false
|
||||||
|
release_completion: true
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# qbit-standard-process-trace
|
||||||
|
|
||||||
|
## Knowledge base
|
||||||
|
|
||||||
|
A reviewed dossier for this repo lives in the second-brain vault:
|
||||||
|
|
||||||
|
- Hub: `$SECOND_BRAIN_VAULT/knowledge/qqq/qqq-hub.md` — map of the whole QQQ knowledge base
|
||||||
|
- Dossier: `$SECOND_BRAIN_VAULT/knowledge/qqq/repos/qbit-standard-process-trace.md`
|
||||||
|
(purpose, API surface, data model, QBit contract usage, licensing state, v4.0 impact)
|
||||||
|
|
||||||
|
Reviewed at commit `0f2ec0339048` (branch `develop`, 2026-07-04).
|
||||||
|
|
||||||
|
Key facts worth knowing before editing:
|
||||||
|
|
||||||
|
- `main` was merged back into `develop` for QRun-IO/qqq#766, so `develop` has main's
|
||||||
|
Java 21 + Apache-2.0 LICENSE/NOTICE and the backend-activity-stats feature. Current
|
||||||
|
first-party pom, source-header and README license declarations also use Apache-2.0.
|
||||||
|
- The qqq version comes only from `qbit-build-parent` 2.0.0 (qqq 4.0.0); do not re-add a
|
||||||
|
`qqq-bom-pom` import. `mvn -B verify -Pqqq-snapshot` checks against qqq `4.1.0-SNAPSHOT`
|
||||||
|
(override with `-Dqqq.snapshot.version=...`).
|
||||||
|
- CHANGELOG.md text is copy-pasted from a different QBit; README code examples have drift
|
||||||
|
(nonexistent `producer.withTableMetaDataCustomizer`, table-name typos).
|
||||||
@@ -24,7 +24,7 @@ This QBit provides automatic tracing for QQQ processes. Every execution is logge
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- QQQ application (v0.35.0+)
|
- QQQ application (v4.1.0+)
|
||||||
- Database backend configured
|
- Database backend configured
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
@@ -132,4 +132,4 @@ Stable and production-ready.
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Proprietary - QRun.IO
|
Apache-2.0 - See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
||||||
@@ -6,27 +6,30 @@
|
|||||||
~ contact@kingsrook.com
|
~ contact@kingsrook.com
|
||||||
~ https://github.com/Kingsrook/
|
~ https://github.com/Kingsrook/
|
||||||
~
|
~
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
~ it under the terms of the GNU Affero General Public License as
|
~ you may not use this file except in compliance with the License.
|
||||||
~ published by the Free Software Foundation, either version 3 of the
|
~ You may obtain a copy of the License at
|
||||||
~ License, or (at your option) any later version.
|
|
||||||
~
|
~
|
||||||
~ This program is distributed in the hope that it will be useful,
|
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU Affero General Public License for more details.
|
|
||||||
~
|
~
|
||||||
~ You should have received a copy of the GNU Affero General Public License
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
~ 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.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
<properties>
|
||||||
|
<revision>0.3.0-SNAPSHOT</revision>
|
||||||
|
<qqq.version>4.1.0-RC.26</qqq.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.kingsrook</groupId>
|
<groupId>com.kingsrook</groupId>
|
||||||
<artifactId>qbit-build-parent</artifactId>
|
<artifactId>qbit-build-parent</artifactId>
|
||||||
<version>1.5.1</version>
|
<version>2.2.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.kingsrook.qbits</groupId>
|
<groupId>com.kingsrook.qbits</groupId>
|
||||||
@@ -38,10 +41,12 @@
|
|||||||
<description>Standard process tracing module for the QBit framework, providing process trace tables and StandardProcessTracer implementation</description>
|
<description>Standard process tracing module for the QBit framework, providing process trace tables and StandardProcessTracer implementation</description>
|
||||||
<url>https://github.com/Kingsrook/qbit-standard-process-trace</url>
|
<url>https://github.com/Kingsrook/qbit-standard-process-trace</url>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>GNU Affero General Public License v3.0</name>
|
<name>Apache License, Version 2.0</name>
|
||||||
<url>https://www.gnu.org/licenses/agpl-3.0.html</url>
|
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
@@ -63,24 +68,20 @@
|
|||||||
<tag>HEAD</tag>
|
<tag>HEAD</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<revision>0.2.0</revision>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Published QQQ 4.1 core (minimum QQQ 4.1), imported ahead of the parent's BOM. -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.kingsrook.qqq</groupId>
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
<artifactId>qqq-bom-pom</artifactId>
|
<artifactId>qqq-bom-pom</artifactId>
|
||||||
<version>0.27.9</version>
|
<version>${qqq.version}</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit</groupId>
|
<groupId>org.junit</groupId>
|
||||||
<artifactId>junit-bom</artifactId>
|
<artifactId>junit-bom</artifactId>
|
||||||
<version>5.10.0</version>
|
<version>6.0.2</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -92,10 +93,6 @@
|
|||||||
<groupId>com.kingsrook.qqq</groupId>
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
<artifactId>qqq-backend-core</artifactId>
|
<artifactId>qqq-backend-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.kingsrook.qqq</groupId>
|
|
||||||
<artifactId>qqq-backend-module-rdbms</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
@@ -105,7 +102,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.assertj</groupId>
|
<groupId>org.assertj</groupId>
|
||||||
<artifactId>assertj-core</artifactId>
|
<artifactId>assertj-core</artifactId>
|
||||||
<version>3.27.3</version>
|
<version>3.27.7</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
+99
-13
@@ -5,33 +5,41 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace;
|
package com.kingsrook.qbits.standardprocesstrace;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** ad-hoc Configuration data for this qbit.
|
* Configuration data for this qbit.
|
||||||
** TODO - when qbit configs become formalized in qqq, adapt this qbit to that interface.
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class StandardProcessTraceQBitConfig
|
public class StandardProcessTraceQBitConfig implements QBitConfig
|
||||||
{
|
{
|
||||||
|
private MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer;
|
||||||
|
|
||||||
private String userIdPossibleValueSourceName;
|
private String userIdPossibleValueSourceName;
|
||||||
private String userTableName;
|
private String userTableName;
|
||||||
private String userIdReferenceFieldName;
|
private String userIdReferenceFieldName;
|
||||||
|
|
||||||
|
private boolean includeBackendActivityStats = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@@ -125,4 +133,82 @@ public class StandardProcessTraceQBitConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for includeBackendActivityStats
|
||||||
|
* @see #withIncludeBackendActivityStats(boolean)
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getIncludeBackendActivityStats()
|
||||||
|
{
|
||||||
|
return (this.includeBackendActivityStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for includeBackendActivityStats
|
||||||
|
* @see #withIncludeBackendActivityStats(boolean)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIncludeBackendActivityStats(boolean includeBackendActivityStats)
|
||||||
|
{
|
||||||
|
this.includeBackendActivityStats = includeBackendActivityStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for includeBackendActivityStats
|
||||||
|
*
|
||||||
|
* @param includeBackendActivityStats
|
||||||
|
* indicate whether or not the ProcessTraceBackendActivityStats table should be
|
||||||
|
* included in the QInstance (and records should be built in that table under
|
||||||
|
* processTrace records).
|
||||||
|
* <p>Note that using this feature requires the QQQ QueryStatManager to be active
|
||||||
|
* in the application server.</p>
|
||||||
|
* @return this
|
||||||
|
*******************************************************************************/
|
||||||
|
public StandardProcessTraceQBitConfig withIncludeBackendActivityStats(boolean includeBackendActivityStats)
|
||||||
|
{
|
||||||
|
this.includeBackendActivityStats = includeBackendActivityStats;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for tableMetaDataCustomizer
|
||||||
|
* @see #withTableMetaDataCustomizer(MetaDataCustomizerInterface)
|
||||||
|
*******************************************************************************/
|
||||||
|
public MetaDataCustomizerInterface<QTableMetaData> getTableMetaDataCustomizer()
|
||||||
|
{
|
||||||
|
return (this.tableMetaDataCustomizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for tableMetaDataCustomizer
|
||||||
|
* @see #withTableMetaDataCustomizer(MetaDataCustomizerInterface)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
||||||
|
{
|
||||||
|
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for tableMetaDataCustomizer
|
||||||
|
*
|
||||||
|
* @param tableMetaDataCustomizer
|
||||||
|
* table meta data customizer to be applied to all tables produced by this qbit.
|
||||||
|
* @return this
|
||||||
|
*******************************************************************************/
|
||||||
|
public StandardProcessTraceQBitConfig withTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
||||||
|
{
|
||||||
|
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+66
-63
@@ -5,33 +5,32 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace;
|
package com.kingsrook.qbits.standardprocesstrace;
|
||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLine;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLine;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLineRecordInt;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLineRecordInt;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerHelper;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput;
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaDataProducer;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
@@ -39,10 +38,9 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class StandardProcessTraceQBitProducer implements MetaDataProducerInterface<MetaDataProducerMultiOutput>
|
public class StandardProcessTraceQBitProducer implements QBitMetaDataProducer<StandardProcessTraceQBitConfig>
|
||||||
{
|
{
|
||||||
private StandardProcessTraceQBitConfig standardProcessTraceQBitConfig;
|
private StandardProcessTraceQBitConfig standardProcessTraceQBitConfig;
|
||||||
private MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -51,35 +49,71 @@ public class StandardProcessTraceQBitProducer implements MetaDataProducerInterfa
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
public static QAppSection getAppSection(QInstance qInstance)
|
public static QAppSection getAppSection(QInstance qInstance)
|
||||||
{
|
{
|
||||||
return (new QAppSection().withName("processTrace")
|
QBitMetaData qBitMetaData = qInstance.getQBits().get(new StandardProcessTraceQBitProducer().getQBitMetaData().getName());
|
||||||
|
|
||||||
|
QAppSection section = new QAppSection().withName("processTrace")
|
||||||
.withTable(ProcessTrace.TABLE_NAME)
|
.withTable(ProcessTrace.TABLE_NAME)
|
||||||
.withTable(ProcessTraceSummaryLine.TABLE_NAME)
|
.withTable(ProcessTraceSummaryLine.TABLE_NAME)
|
||||||
.withTable(ProcessTraceSummaryLineRecordInt.TABLE_NAME));
|
.withTable(ProcessTraceSummaryLineRecordInt.TABLE_NAME);
|
||||||
|
|
||||||
|
if(qBitMetaData != null && qBitMetaData.getConfig() instanceof StandardProcessTraceQBitConfig config)
|
||||||
|
{
|
||||||
|
if(config.getIncludeBackendActivityStats())
|
||||||
|
{
|
||||||
|
section.withTable(ProcessTraceBackendActivityStats.TABLE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (section);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
**
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@Override
|
@Override
|
||||||
public MetaDataProducerMultiOutput produce(QInstance qInstance) throws QException
|
public StandardProcessTraceQBitConfig getQBitConfig()
|
||||||
{
|
{
|
||||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, ProcessTrace.class.getPackageName(), tableMetaDataCustomizer);
|
return (standardProcessTraceQBitConfig);
|
||||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, getClass().getPackageName() + ".metadata", tableMetaDataCustomizer);
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// set the possible value source on the processTrace.userId field, if so configured //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
/***************************************************************************
|
||||||
if(standardProcessTraceQBitConfig != null && StringUtils.hasContent(standardProcessTraceQBitConfig.getUserIdPossibleValueSourceName()))
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QBitMetaData getQBitMetaData()
|
||||||
|
{
|
||||||
|
QBitMetaData qBitMetaData = new QBitMetaData()
|
||||||
|
.withGroupId("com.kingsrook.qbits")
|
||||||
|
.withArtifactId("standard-process-trace")
|
||||||
|
.withVersion("0.1.3")
|
||||||
|
.withNamespace(getNamespace())
|
||||||
|
.withConfig(getQBitConfig());
|
||||||
|
|
||||||
|
return qBitMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void postProduceActions(MetaDataProducerMultiOutput metaDataProducerMultiOutput, QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
if(standardProcessTraceQBitConfig != null)
|
||||||
{
|
{
|
||||||
qInstance.getTable(ProcessTrace.TABLE_NAME).getField("userId").setPossibleValueSourceName(standardProcessTraceQBitConfig.getUserIdPossibleValueSourceName());
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// set the possible value source on the processTrace.userId field, if so configured //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(StringUtils.hasContent(standardProcessTraceQBitConfig.getUserIdPossibleValueSourceName()))
|
||||||
|
{
|
||||||
|
metaDataProducerMultiOutput.get(QTableMetaData.class, ProcessTrace.TABLE_NAME).getField("userId").setPossibleValueSourceName(standardProcessTraceQBitConfig.getUserIdPossibleValueSourceName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// we actually called MetaDataProducerHelper ourselves, so, don't have anything to return here... //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
return new MetaDataProducerMultiOutput();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -113,35 +147,4 @@ public class StandardProcessTraceQBitProducer implements MetaDataProducerInterfa
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Getter for tableMetaDataCustomizer
|
|
||||||
*******************************************************************************/
|
|
||||||
public MetaDataCustomizerInterface<QTableMetaData> getTableMetaDataCustomizer()
|
|
||||||
{
|
|
||||||
return (this.tableMetaDataCustomizer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Setter for tableMetaDataCustomizer
|
|
||||||
*******************************************************************************/
|
|
||||||
public void setTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
|
||||||
{
|
|
||||||
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Fluent setter for tableMetaDataCustomizer
|
|
||||||
*******************************************************************************/
|
|
||||||
public StandardProcessTraceQBitProducer withTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
|
|
||||||
{
|
|
||||||
this.tableMetaDataCustomizer = tableMetaDataCustomizer;
|
|
||||||
return (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStatsAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Meta Data Producer for ProcessTraceBackendActivityStatsAction
|
||||||
|
* Note: not done via annotations, so it can be disabled via config
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceBackendActivityStatsActionMetaDataProducer extends MetaDataProducer<QPossibleValueSource>
|
||||||
|
{
|
||||||
|
public static final String NAME = ProcessTraceBackendActivityStatsAction.NAME;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return (new ProcessTraceBackendActivityStatsMetaDataProducer().isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QPossibleValueSource produce(QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
return (QPossibleValueSource.newForEnum(NAME, ProcessTraceBackendActivityStatsAction.values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.StandardProcessTraceQBitConfig;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitProductionContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.SectionFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Meta Data Producer for ProcessTraceBackendActivityStats
|
||||||
|
* Note: not done via annotations, so it can be disabled via config
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceBackendActivityStatsMetaDataProducer extends MetaDataProducer<QTableMetaData>
|
||||||
|
{
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
QBitConfig qBitConfig = QBitProductionContext.peekQBitConfig();
|
||||||
|
if(qBitConfig instanceof StandardProcessTraceQBitConfig config)
|
||||||
|
{
|
||||||
|
if(!config.getIncludeBackendActivityStats())
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData()
|
||||||
|
.withName(ProcessTraceBackendActivityStats.TABLE_NAME)
|
||||||
|
.withIcon(new QIcon().withName("query_stats"))
|
||||||
|
.withRecordLabelFormat("%s %s %s %s")
|
||||||
|
.withRecordLabelFields("processTraceId", "qqqBackendId", "qqqTableId", "actionName")
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withFieldsFromEntity(ProcessTraceBackendActivityStats.class)
|
||||||
|
.withSection(SectionFactory.defaultT1("id", "processTraceId", "qqqBackendId", "qqqTableId", "actionName"))
|
||||||
|
.withSection(SectionFactory.defaultT2("callCount", "recordCount", "runtimeMillis"))
|
||||||
|
.withExposedJoin(new ExposedJoin().withLabel("Process Trace").withJoinPath(List.of(ProcessTraceJoinBackendActivityStatsMetaDataProducer.NAME)).withJoinTable(ProcessTrace.TABLE_NAME));
|
||||||
|
|
||||||
|
table.withoutCapabilities(Capability.allWriteCapabilities());
|
||||||
|
|
||||||
|
QInstanceEnricher.setInferredFieldBackendNames(table);
|
||||||
|
|
||||||
|
return (table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Meta Data Producer for ProcessTraceJoinBackendActivityStats
|
||||||
|
* Note: not done via annotations, so it can be disabled via config
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceJoinBackendActivityStatsMetaDataProducer extends MetaDataProducer<QJoinMetaData>
|
||||||
|
{
|
||||||
|
public static final String NAME = "ProcessTraceJoinBackendActivityStats";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return (new ProcessTraceBackendActivityStatsMetaDataProducer().isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QJoinMetaData produce(QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
return (new QJoinMetaData()
|
||||||
|
.withName(NAME)
|
||||||
|
.withLeftTable(ProcessTrace.TABLE_NAME)
|
||||||
|
.withRightTable(ProcessTraceBackendActivityStats.TABLE_NAME)
|
||||||
|
.withType(JoinType.ONE_TO_MANY)
|
||||||
|
.withJoinOn(new JoinOn("id", "processTraceId"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ChildRecordListRenderer;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitProductionContext;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Meta Data Producer for ProcessTraceJoinBackendActivityStats
|
||||||
|
* Note: not done via annotations, so it can be disabled via config
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceJoinBackendActivityStatsWidgetMetaDataProducer extends MetaDataProducer<QWidgetMetaData>
|
||||||
|
{
|
||||||
|
public static final String NAME = "ProcessTraceJoinBackendActivityStatsWidget";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return (new ProcessTraceBackendActivityStatsMetaDataProducer().isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QWidgetMetaData produce(QInstance qInstance) throws QException
|
||||||
|
{
|
||||||
|
MetaDataProducerMultiOutput metaDataProducerMultiOutput = QBitProductionContext.peekMetaDataProducerMultiOutput();
|
||||||
|
QJoinMetaData joinMetaData = metaDataProducerMultiOutput.get(QJoinMetaData.class, ProcessTraceJoinBackendActivityStatsMetaDataProducer.NAME);
|
||||||
|
|
||||||
|
return ChildRecordListRenderer.widgetMetaDataBuilder(joinMetaData)
|
||||||
|
.withName(NAME)
|
||||||
|
.withLabel("Backend Activity Stats")
|
||||||
|
.withMaxRows(250)
|
||||||
|
.getWidgetMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
package com.kingsrook.qbits.standardprocesstrace.metadata;
|
||||||
|
|||||||
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.model;
|
package com.kingsrook.qbits.standardprocesstrace.model;
|
||||||
@@ -24,6 +23,9 @@ package com.kingsrook.qbits.standardprocesstrace.model;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceBackendActivityStatsMetaDataProducer;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinBackendActivityStatsMetaDataProducer;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinBackendActivityStatsWidgetMetaDataProducer;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinKeyRecordQQQTableMetaDataProducer;
|
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinKeyRecordQQQTableMetaDataProducer;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinQQQProcessMetaDataProducer;
|
import com.kingsrook.qbits.standardprocesstrace.metadata.ProcessTraceJoinQQQProcessMetaDataProducer;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.utils.ProcessTraceTableCustomizer;
|
import com.kingsrook.qbits.standardprocesstrace.utils.ProcessTraceTableCustomizer;
|
||||||
@@ -66,7 +68,7 @@ import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
|
|||||||
childTableEntityClass = ProcessTraceSummaryLine.class,
|
childTableEntityClass = ProcessTraceSummaryLine.class,
|
||||||
joinFieldName = "processTraceSummaryLineId",
|
joinFieldName = "processTraceSummaryLineId",
|
||||||
childJoin = @ChildJoin(enabled = true),
|
childJoin = @ChildJoin(enabled = true),
|
||||||
childRecordListWidget = @ChildRecordListWidget(label = "Summary Lines", enabled = true, maxRows = 250))
|
childRecordListWidget = @ChildRecordListWidget(label = "Summary Lines", enabled = true, maxRows = 250)),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public class ProcessTrace extends QRecordEntity
|
public class ProcessTrace extends QRecordEntity
|
||||||
@@ -87,7 +89,7 @@ public class ProcessTrace extends QRecordEntity
|
|||||||
@Override
|
@Override
|
||||||
public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException
|
public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException
|
||||||
{
|
{
|
||||||
String childJoinName = QJoinMetaData.makeInferredJoinName(TABLE_NAME, ProcessTraceSummaryLine.TABLE_NAME);
|
String summaryLinesChildJoinName = QJoinMetaData.makeInferredJoinName(TABLE_NAME, ProcessTraceSummaryLine.TABLE_NAME);
|
||||||
|
|
||||||
table
|
table
|
||||||
.withUniqueKey(new UniqueKey("processUUID"))
|
.withUniqueKey(new UniqueKey("processUUID"))
|
||||||
@@ -96,14 +98,25 @@ public class ProcessTrace extends QRecordEntity
|
|||||||
.withRecordLabelFields("qqqProcessId", "processUUID")
|
.withRecordLabelFields("qqqProcessId", "processUUID")
|
||||||
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "qqqProcessId", "processUUID", "userId")))
|
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "qqqProcessId", "processUUID", "userId")))
|
||||||
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("startTimestamp", "endTimestamp", "runtimeMillis", "keyRecordQqqTableId", "keyRecordId", "recordCount", "exceptionMessage")))
|
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("startTimestamp", "endTimestamp", "runtimeMillis", "keyRecordQqqTableId", "keyRecordId", "recordCount", "exceptionMessage")))
|
||||||
.withSection(new QFieldSection("summaryLines", new QIcon().withName("horizontal_rule"), Tier.T2).withWidgetName(childJoinName))
|
.withSection(new QFieldSection("summaryLines", new QIcon().withName("horizontal_rule"), Tier.T2).withWidgetName(summaryLinesChildJoinName))
|
||||||
.withExposedJoin(new ExposedJoin().withLabel("Summary Lines").withJoinPath(List.of(childJoinName)).withJoinTable(ProcessTraceSummaryLine.TABLE_NAME))
|
.withExposedJoin(new ExposedJoin().withLabel("Summary Lines").withJoinPath(List.of(summaryLinesChildJoinName)).withJoinTable(ProcessTraceSummaryLine.TABLE_NAME))
|
||||||
.withExposedJoin(new ExposedJoin().withLabel("Key Record Table").withJoinPath(List.of(ProcessTraceJoinKeyRecordQQQTableMetaDataProducer.NAME)).withJoinTable(QQQTable.TABLE_NAME))
|
.withExposedJoin(new ExposedJoin().withLabel("Key Record Table").withJoinPath(List.of(ProcessTraceJoinKeyRecordQQQTableMetaDataProducer.NAME)).withJoinTable(QQQTable.TABLE_NAME))
|
||||||
.withExposedJoin(new ExposedJoin().withLabel("Process").withJoinPath(List.of(ProcessTraceJoinQQQProcessMetaDataProducer.NAME)).withJoinTable(QQQProcess.TABLE_NAME));
|
.withExposedJoin(new ExposedJoin().withLabel("Process").withJoinPath(List.of(ProcessTraceJoinQQQProcessMetaDataProducer.NAME)).withJoinTable(QQQProcess.TABLE_NAME));
|
||||||
|
|
||||||
table.withCustomizer(TableCustomizers.POST_QUERY_RECORD, new QCodeReference(ProcessTraceTableCustomizer.class));
|
table.withCustomizer(TableCustomizers.POST_QUERY_RECORD, new QCodeReference(ProcessTraceTableCustomizer.class));
|
||||||
table.getField("keyRecordId").withFieldAdornment(new FieldAdornment(AdornmentType.LINK).withValue(AdornmentType.LinkValues.TO_RECORD_FROM_TABLE_DYNAMIC, true));
|
table.getField("keyRecordId").withFieldAdornment(new FieldAdornment(AdornmentType.LINK).withValue(AdornmentType.LinkValues.TO_RECORD_FROM_TABLE_DYNAMIC, true));
|
||||||
|
|
||||||
|
if(new ProcessTraceBackendActivityStatsMetaDataProducer().isEnabled())
|
||||||
|
{
|
||||||
|
table.getSections().add(new QFieldSection("backendActivityStats", new QIcon().withName("query_stats"), Tier.T2)
|
||||||
|
.withWidgetName(ProcessTraceJoinBackendActivityStatsWidgetMetaDataProducer.NAME));
|
||||||
|
|
||||||
|
table.withExposedJoin(new ExposedJoin()
|
||||||
|
.withLabel("Backend Activity Stats")
|
||||||
|
.withJoinPath(List.of(ProcessTraceJoinBackendActivityStatsMetaDataProducer.NAME))
|
||||||
|
.withJoinTable(ProcessTraceBackendActivityStats.TABLE_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
return (table);
|
return (table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+348
@@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.model;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.backends.QQQBackend;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* QRecord Entity for ProcessTraceBackendActivityStats table
|
||||||
|
* Note: not using meta-data producing annotations, so it can be disabled via config
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceBackendActivityStats extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "processTraceBackendActivityStats";
|
||||||
|
|
||||||
|
@QField(isEditable = false, isPrimaryKey = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@QField(possibleValueSourceName = ProcessTrace.TABLE_NAME)
|
||||||
|
private Long processTraceId;
|
||||||
|
|
||||||
|
@QField(label = "Backend", possibleValueSourceName = QQQBackend.TABLE_NAME)
|
||||||
|
private Integer qqqBackendId;
|
||||||
|
|
||||||
|
@QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME)
|
||||||
|
private Integer qqqTableId;
|
||||||
|
|
||||||
|
@QField(label = "Action", possibleValueSourceName = ProcessTraceBackendActivityStatsAction.NAME)
|
||||||
|
private String actionName;
|
||||||
|
|
||||||
|
@QField(displayFormat = DisplayFormat.COMMAS)
|
||||||
|
private Integer callCount;
|
||||||
|
|
||||||
|
@QField(displayFormat = DisplayFormat.COMMAS)
|
||||||
|
private Integer recordCount;
|
||||||
|
|
||||||
|
@QField(displayFormat = DisplayFormat.COMMAS)
|
||||||
|
private Integer runtimeMillis;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Default constructor
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor that takes a QRecord
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats(QRecord record)
|
||||||
|
{
|
||||||
|
populateFromQRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for id
|
||||||
|
* @see #withId(Long)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Long getId()
|
||||||
|
{
|
||||||
|
return (this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for id
|
||||||
|
* @see #withId(Long)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Long id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for id
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withId(Long id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for processTraceId
|
||||||
|
* @see #withProcessTraceId(Long)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Long getProcessTraceId()
|
||||||
|
{
|
||||||
|
return (this.processTraceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for processTraceId
|
||||||
|
* @see #withProcessTraceId(Long)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setProcessTraceId(Long processTraceId)
|
||||||
|
{
|
||||||
|
this.processTraceId = processTraceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for processTraceId
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withProcessTraceId(Long processTraceId)
|
||||||
|
{
|
||||||
|
this.processTraceId = processTraceId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for actionName
|
||||||
|
* @see #withActionName(String)
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getActionName()
|
||||||
|
{
|
||||||
|
return (this.actionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for actionName
|
||||||
|
* @see #withActionName(String)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setActionName(String actionName)
|
||||||
|
{
|
||||||
|
this.actionName = actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for actionName
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withActionName(String actionName)
|
||||||
|
{
|
||||||
|
this.actionName = actionName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for callCount
|
||||||
|
* @see #withCallCount(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getCallCount()
|
||||||
|
{
|
||||||
|
return (this.callCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for callCount
|
||||||
|
* @see #withCallCount(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCallCount(Integer callCount)
|
||||||
|
{
|
||||||
|
this.callCount = callCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for callCount
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withCallCount(Integer callCount)
|
||||||
|
{
|
||||||
|
this.callCount = callCount;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for recordCount
|
||||||
|
* @see #withRecordCount(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getRecordCount()
|
||||||
|
{
|
||||||
|
return (this.recordCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for recordCount
|
||||||
|
* @see #withRecordCount(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordCount(Integer recordCount)
|
||||||
|
{
|
||||||
|
this.recordCount = recordCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for recordCount
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withRecordCount(Integer recordCount)
|
||||||
|
{
|
||||||
|
this.recordCount = recordCount;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for runtimeMillis
|
||||||
|
* @see #withRuntimeMillis(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getRuntimeMillis()
|
||||||
|
{
|
||||||
|
return (this.runtimeMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for runtimeMillis
|
||||||
|
* @see #withRuntimeMillis(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRuntimeMillis(Integer runtimeMillis)
|
||||||
|
{
|
||||||
|
this.runtimeMillis = runtimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for runtimeMillis
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withRuntimeMillis(Integer runtimeMillis)
|
||||||
|
{
|
||||||
|
this.runtimeMillis = runtimeMillis;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for qqqBackendId
|
||||||
|
* @see #withQqqBackendId(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getQqqBackendId()
|
||||||
|
{
|
||||||
|
return (this.qqqBackendId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for qqqBackendId
|
||||||
|
* @see #withQqqBackendId(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setQqqBackendId(Integer qqqBackendId)
|
||||||
|
{
|
||||||
|
this.qqqBackendId = qqqBackendId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for qqqBackendId
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withQqqBackendId(Integer qqqBackendId)
|
||||||
|
{
|
||||||
|
this.qqqBackendId = qqqBackendId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Getter for qqqTableId
|
||||||
|
* @see #withQqqTableId(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getQqqTableId()
|
||||||
|
{
|
||||||
|
return (this.qqqTableId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Setter for qqqTableId
|
||||||
|
* @see #withQqqTableId(Integer)
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setQqqTableId(Integer qqqTableId)
|
||||||
|
{
|
||||||
|
this.qqqTableId = qqqTableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Fluent setter for qqqTableId
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessTraceBackendActivityStats withQqqTableId(Integer qqqTableId)
|
||||||
|
{
|
||||||
|
this.qqqTableId = qqqTableId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.model;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditDetailAccumulator;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** ProcessTraceBackendActivityStatsAction - possible value enum
|
||||||
|
*******************************************************************************/
|
||||||
|
public enum ProcessTraceBackendActivityStatsAction implements PossibleValueEnum<String>
|
||||||
|
{
|
||||||
|
INSERT(InsertAction.class.getSimpleName(), "Insert"),
|
||||||
|
UPDATE(UpdateAction.class.getSimpleName(), "Update"),
|
||||||
|
DELETE(DeleteAction.class.getSimpleName(), "Delete"),
|
||||||
|
QUERY(QueryAction.class.getSimpleName(), "Query"),
|
||||||
|
GET(GetAction.class.getSimpleName(), "Get"),
|
||||||
|
COUNT(CountAction.class.getSimpleName(), "Count"),
|
||||||
|
AGGREGATE(AuditDetailAccumulator.class.getSimpleName(), "Aggregate");
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String label;
|
||||||
|
|
||||||
|
public static final String NAME = "ProcessTraceBackendActivityStatsAction";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
ProcessTraceBackendActivityStatsAction(String id, String label)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Get instance by id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static ProcessTraceBackendActivityStatsAction getById(String id)
|
||||||
|
{
|
||||||
|
if(id == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ProcessTraceBackendActivityStatsAction value : ProcessTraceBackendActivityStatsAction.values())
|
||||||
|
{
|
||||||
|
if(Objects.equals(value.id, id))
|
||||||
|
{
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for label
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getLabel()
|
||||||
|
{
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String getPossibleValueId()
|
||||||
|
{
|
||||||
|
return (getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String getPossibleValueLabel()
|
||||||
|
{
|
||||||
|
return (getLabel());
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.model;
|
package com.kingsrook.qbits.standardprocesstrace.model;
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.model;
|
package com.kingsrook.qbits.standardprocesstrace.model;
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+297
@@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.backends.QQQBackendTableManager;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.tables.QQQTableTableManager;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.PrefixedDefaultThreadFactory;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Singleton that collects QueryStats, associated with a processTraceId.
|
||||||
|
*
|
||||||
|
* <p>Runs a scheduled executor thread to clean itself up - e.g., in case processes
|
||||||
|
* leak (e.g., started in a frontend but exited before final step). Configured by
|
||||||
|
* {@link #setCleanupIntervalMillis(long)} and {@link #setCleanupMaxAge(long)}</p>
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ProcessTraceBackendActivityStatsManager
|
||||||
|
{
|
||||||
|
private static final QLogger LOG = QLogger.getLogger(ProcessTraceBackendActivityStatsManager.class);
|
||||||
|
|
||||||
|
private static ProcessTraceBackendActivityStatsManager processTraceBackendActivityStatsManager = null;
|
||||||
|
|
||||||
|
private Map<Long, ProcessStats> stats = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
private long CLEANUP_INTERVAL_MILLIS = 60 * 60 * 1000;
|
||||||
|
private long CLEANUP_MAX_AGE = 12 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* container for all data collected for a particular process trace.
|
||||||
|
*
|
||||||
|
* stores start milliseconds (for cleanup), plus map of keys to stats.
|
||||||
|
***************************************************************************/
|
||||||
|
private record ProcessStats(long startMillis, Map<Key, Stats> stats)
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor that uses default values
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ProcessStats()
|
||||||
|
{
|
||||||
|
this(System.currentTimeMillis(), new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* what backend/table/action a set of stats are associated with.
|
||||||
|
*
|
||||||
|
* e.g., memoryBackend, personTable, insertAction
|
||||||
|
***************************************************************************/
|
||||||
|
public record Key(String backendName, String tableName, String actionName) implements Serializable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* the stats collected for individual keys.
|
||||||
|
***************************************************************************/
|
||||||
|
private record Stats(Integer calls, Integer records, Integer millis)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Singleton constructor
|
||||||
|
*******************************************************************************/
|
||||||
|
private ProcessTraceBackendActivityStatsManager()
|
||||||
|
{
|
||||||
|
scheduleCleanupJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
private void scheduleCleanupJob()
|
||||||
|
{
|
||||||
|
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new PrefixedDefaultThreadFactory("ProcessTraceBackendActivityStatsManager-cleanup"));
|
||||||
|
scheduledExecutorService.scheduleAtFixedRate(this::cleanup, CLEANUP_INTERVAL_MILLIS, CLEANUP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Singleton accessor
|
||||||
|
*******************************************************************************/
|
||||||
|
public static ProcessTraceBackendActivityStatsManager getInstance()
|
||||||
|
{
|
||||||
|
if(processTraceBackendActivityStatsManager == null)
|
||||||
|
{
|
||||||
|
processTraceBackendActivityStatsManager = new ProcessTraceBackendActivityStatsManager();
|
||||||
|
}
|
||||||
|
return (processTraceBackendActivityStatsManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* shutdown the scheduled job. also clear stats.
|
||||||
|
***************************************************************************/
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
scheduledExecutorService.shutdown();
|
||||||
|
stats.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* initialize storage for stats for a specific process trace id
|
||||||
|
***************************************************************************/
|
||||||
|
public void initProcess(Long processTraceId)
|
||||||
|
{
|
||||||
|
stats.put(processTraceId, new ProcessStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* clean up stat entries for processes that were originally created before
|
||||||
|
* CLEANUP_MAX_AGE (per {@link #setCleanupMaxAge(long)} milliseconds ago.
|
||||||
|
***************************************************************************/
|
||||||
|
private void cleanup()
|
||||||
|
{
|
||||||
|
long limitStartMillis = System.currentTimeMillis() - CLEANUP_MAX_AGE;
|
||||||
|
LOG.info("Starting cleanup of ProcessTraceBackendActivityStatsManager", logPair("size", stats.size()));
|
||||||
|
stats.entrySet().removeIf(entry -> entry.getValue().startMillis < limitStartMillis);
|
||||||
|
LOG.info("Finished cleanup of ProcessTraceBackendActivityStatsManager", logPair("size", stats.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* when storing a processTrace (e.g., after the process has finished running),
|
||||||
|
* convert the stats stored in this object to a list of {@link ProcessTraceBackendActivityStats}
|
||||||
|
* entities. Also remove the stats from this object's internal storage.
|
||||||
|
***************************************************************************/
|
||||||
|
public List<ProcessTraceBackendActivityStats> getAndRemoveStats(Long processTraceId) throws QException
|
||||||
|
{
|
||||||
|
List<ProcessTraceBackendActivityStats> rs = new ArrayList<>();
|
||||||
|
|
||||||
|
ProcessStats processStats = stats.remove(processTraceId);
|
||||||
|
if(processStats != null)
|
||||||
|
{
|
||||||
|
for(Map.Entry<Key, Stats> entry : CollectionUtils.nonNullMap(processStats.stats()).entrySet())
|
||||||
|
{
|
||||||
|
rs.add(new ProcessTraceBackendActivityStats()
|
||||||
|
.withProcessTraceId(processTraceId)
|
||||||
|
.withQqqBackendId(getBackendId(entry.getKey().backendName()))
|
||||||
|
.withQqqTableId(getTableId(entry.getKey().tableName()))
|
||||||
|
.withActionName(entry.getKey().actionName())
|
||||||
|
.withCallCount(entry.getValue().calls())
|
||||||
|
.withRecordCount(entry.getValue().records())
|
||||||
|
.withRuntimeMillis(entry.getValue().millis())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
private Integer getBackendId(String backendName)
|
||||||
|
{
|
||||||
|
if(!StringUtils.hasContent(backendName))
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return QQQBackendTableManager.getQQQBackendId(QContext.getQInstance(), backendName);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
private Integer getTableId(String tableName)
|
||||||
|
{
|
||||||
|
if(!StringUtils.hasContent(tableName))
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return QQQTableTableManager.getQQQTableId(QContext.getQInstance(), tableName);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* increment the stat values for a given process.
|
||||||
|
*
|
||||||
|
* @param key the backend, table, and action
|
||||||
|
* @param addCalls the number of calls to add (typically 1 at a time?)
|
||||||
|
* @param addRecords the number of records to add
|
||||||
|
* @param addMillis the number of milliseconds of runtime to add
|
||||||
|
***************************************************************************/
|
||||||
|
public void add(Long processTraceId, Key key, Integer addCalls, Integer addRecords, Integer addMillis)
|
||||||
|
{
|
||||||
|
ProcessStats processStats = stats.computeIfAbsent(processTraceId, k -> new ProcessStats());
|
||||||
|
Map<Key, Stats> countsForProcess = processStats.stats();
|
||||||
|
|
||||||
|
if(countsForProcess != null)
|
||||||
|
{
|
||||||
|
Stats statsForKey = countsForProcess.computeIfAbsent(key, (k) -> new Stats(0, 0, 0));
|
||||||
|
countsForProcess.put(key, new Stats(statsForKey.calls + addCalls, statsForKey.records + addRecords, statsForKey.millis + addMillis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* sets the cleanup job's scheduled interval. Also reschedules the job.
|
||||||
|
*
|
||||||
|
* @param cleanupIntervalMillis milliseconds between runs of the cleanup job
|
||||||
|
***************************************************************************/
|
||||||
|
public void setCleanupIntervalMillis(long cleanupIntervalMillis)
|
||||||
|
{
|
||||||
|
CLEANUP_INTERVAL_MILLIS = cleanupIntervalMillis;
|
||||||
|
scheduledExecutorService.shutdown();
|
||||||
|
scheduleCleanupJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* @param cleanupMaxAge max age (in millis) that a process is allowed to be
|
||||||
|
* before it gets cleaned up when a cleanup job runs.
|
||||||
|
***************************************************************************/
|
||||||
|
public void setCleanupMaxAge(long cleanupMaxAge)
|
||||||
|
{
|
||||||
|
CLEANUP_MAX_AGE = cleanupMaxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.utils;
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.utils;
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|||||||
+9
-10
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.kingsrook.qbits.standardprocesstrace.utils;
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.helpers.QueryStatConsumerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.querystats.QueryStat;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Standard Process Trace's implementation of a QueryStat consumer.
|
||||||
|
*
|
||||||
|
* <p>That is, to accumulate them in the {@link ProcessTraceBackendActivityStatsManager},
|
||||||
|
* associated with the processTraceId in the user's session, so they can be stored
|
||||||
|
* when the process trace is stored.</p>
|
||||||
|
*******************************************************************************/
|
||||||
|
public class StandardProcessTraceQueryStatConsumer implements QueryStatConsumerInterface
|
||||||
|
{
|
||||||
|
private static final QLogger LOG = QLogger.getLogger(StandardProcessTraceQueryStatConsumer.class);
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void accept(QueryStat queryStat)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String processTraceId = QContext.getQSession().getValue(StandardProcessTracer.PROCESS_TRACE_ID_SESSION_KEY);
|
||||||
|
if(processTraceId == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String backendName = QContext.getQInstance().getBackendForTable(queryStat.getTableName()).getName();
|
||||||
|
String backendAction = queryStat.getBackendAction();
|
||||||
|
|
||||||
|
ProcessTraceBackendActivityStatsManager.Key key = new ProcessTraceBackendActivityStatsManager.Key(backendName, queryStat.getTableName(), backendAction);
|
||||||
|
ProcessTraceBackendActivityStatsManager.getInstance().add(Long.valueOf(processTraceId), key, 1, queryStat.getRecordCount(), queryStat.getFirstResultMillis());
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error accepting query stats for process trace", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
-13
@@ -5,18 +5,17 @@
|
|||||||
* contact@kingsrook.com
|
* contact@kingsrook.com
|
||||||
* https://github.com/Kingsrook/
|
* https://github.com/Kingsrook/
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* you may not use this file except in compliance with the License.
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* You may obtain a copy of the License at
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -30,6 +29,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.StandardProcessTraceQBitConfig;
|
import com.kingsrook.qbits.standardprocesstrace.StandardProcessTraceQBitConfig;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLine;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLine;
|
||||||
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLineRecordInt;
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLineRecordInt;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
@@ -75,6 +75,8 @@ public class StandardProcessTracer implements ProcessTracerInterface
|
|||||||
|
|
||||||
private static StandardProcessTraceQBitConfig standardProcessTraceQBitConfig;
|
private static StandardProcessTraceQBitConfig standardProcessTraceQBitConfig;
|
||||||
|
|
||||||
|
public static final String PROCESS_TRACE_ID_SESSION_KEY = StandardProcessTracer.class.getName() + ".processTraceId";
|
||||||
|
|
||||||
private Instant startTime;
|
private Instant startTime;
|
||||||
private Long processTraceId;
|
private Long processTraceId;
|
||||||
|
|
||||||
@@ -98,6 +100,17 @@ public class StandardProcessTracer implements ProcessTracerInterface
|
|||||||
.withProcessUUID(runProcessInput.getProcessUUID())));
|
.withProcessUUID(runProcessInput.getProcessUUID())));
|
||||||
|
|
||||||
processTraceId = insertOutput.getRecords().get(0).getValueLong("id");
|
processTraceId = insertOutput.getRecords().get(0).getValueLong("id");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// store the processTraceId in the session. this will be used by the //
|
||||||
|
// ProcessTraceQueryStatConsumer to associated QueryStats with this process trace //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(QContext.getQSession() != null)
|
||||||
|
{
|
||||||
|
QContext.getQSession().setValue(PROCESS_TRACE_ID_SESSION_KEY, String.valueOf(processTraceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessTraceBackendActivityStatsManager.getInstance().initProcess(processTraceId);
|
||||||
}
|
}
|
||||||
catch(QException e)
|
catch(QException e)
|
||||||
{
|
{
|
||||||
@@ -113,9 +126,29 @@ public class StandardProcessTracer implements ProcessTracerInterface
|
|||||||
@Override
|
@Override
|
||||||
public void handleProcessResume(RunProcessInput runProcessInput)
|
public void handleProcessResume(RunProcessInput runProcessInput)
|
||||||
{
|
{
|
||||||
/////////////////////////////////
|
try
|
||||||
// noop in this implementation //
|
{
|
||||||
/////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if a user is resuming a process, e.g., from a frontend, then we want to put that processTraceId in their session //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(processTraceId == null)
|
||||||
|
{
|
||||||
|
QRecord processTrace = GetAction.execute(ProcessTrace.TABLE_NAME, Map.of("processUUID", runProcessInput.getProcessUUID()));
|
||||||
|
if(processTrace != null)
|
||||||
|
{
|
||||||
|
processTraceId = processTrace.getValueLong("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(processTraceId != null && QContext.getQSession() != null)
|
||||||
|
{
|
||||||
|
QContext.getQSession().setValue(PROCESS_TRACE_ID_SESSION_KEY, String.valueOf(processTraceId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error resuming process trace", e, logPair("processUUID", () -> runProcessInput.getProcessUUID()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -328,12 +361,28 @@ public class StandardProcessTracer implements ProcessTracerInterface
|
|||||||
|
|
||||||
new InsertAction().execute(new InsertInput(ProcessTraceSummaryLine.TABLE_NAME).withRecordEntities(summaryLines));
|
new InsertAction().execute(new InsertInput(ProcessTraceSummaryLine.TABLE_NAME).withRecordEntities(summaryLines));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// build and store backend stat records //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
if(QContext.getQInstance().getTable(ProcessTraceBackendActivityStats.TABLE_NAME) != null)
|
||||||
|
{
|
||||||
|
List<ProcessTraceBackendActivityStats> stats = ProcessTraceBackendActivityStatsManager.getInstance().getAndRemoveStats(processTraceId);
|
||||||
|
new InsertAction().execute(new InsertInput(ProcessTraceBackendActivityStats.TABLE_NAME).withRecordEntities(stats));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Error completing store of processTrace records.", e);
|
LOG.warn("Error completing store of processTrace records.", e);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if(QContext.getQSession() != null)
|
||||||
|
{
|
||||||
|
QContext.getQSession().removeValue(PROCESS_TRACE_ID_SESSION_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.utils.StandardProcessTraceQueryStatConsumer;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.helpers.QueryStatManager;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* base class for tests for this QBit.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
void baseBeforeEach() throws Exception
|
||||||
|
{
|
||||||
|
QInstance qInstance = defineQInstance();
|
||||||
|
new QInstanceValidator().validate(qInstance);
|
||||||
|
QContext.init(qInstance, new QSystemUserSession());
|
||||||
|
|
||||||
|
QueryStatManager queryStatManager = QueryStatManager.getInstance();
|
||||||
|
queryStatManager.start(qInstance, () -> new QSystemUserSession());
|
||||||
|
queryStatManager.setQueryStatConsumers(List.of(new StandardProcessTraceQueryStatConsumer()));
|
||||||
|
|
||||||
|
MemoryRecordStore.fullReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@AfterEach
|
||||||
|
void afterEach()
|
||||||
|
{
|
||||||
|
MemoryRecordStore.fullReset();
|
||||||
|
|
||||||
|
QueryStatManager.getInstance().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
private QInstance defineQInstance() throws QException
|
||||||
|
{
|
||||||
|
return new StandardProcessTraceTestApplication().defineQInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+233
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.utils.StandardProcessTracer;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.AbstractQQQApplication;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.Status;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.backends.QQQBackendsMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerMultiOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.audits.QAuditRules;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.processes.QQQProcessesMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.tables.QQQTablesMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.AbstractTransformStep;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.ExtractViaQueryStep;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.LoadViaInsertStep;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* test application (e.g., QInstance) for this QBit's tests.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class StandardProcessTraceTestApplication extends AbstractQQQApplication
|
||||||
|
{
|
||||||
|
public static final String MEMORY_BACKEND_NAME = "memory";
|
||||||
|
|
||||||
|
public static final String TABLE_NAME_PERSON = "person";
|
||||||
|
public static final String TABLE_NAME_ORDER = "order";
|
||||||
|
|
||||||
|
public static final String PROCESS_NAME_PLACE_ORDERS = "placeOrders";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QInstance defineQInstance() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = new QInstance();
|
||||||
|
|
||||||
|
qInstance.withInstanceDefaultAuthentication(new QAuthenticationMetaData().withType(QAuthenticationType.FULLY_ANONYMOUS));
|
||||||
|
|
||||||
|
qInstance.addBackend(new QBackendMetaData()
|
||||||
|
.withName(MEMORY_BACKEND_NAME)
|
||||||
|
.withBackendType(MemoryBackendModule.class));
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// add tables table and PVS //
|
||||||
|
//////////////////////////////
|
||||||
|
new QQQTablesMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, MEMORY_BACKEND_NAME, null);
|
||||||
|
new QQQProcessesMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, MEMORY_BACKEND_NAME, null);
|
||||||
|
new QQQBackendsMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, MEMORY_BACKEND_NAME, null);
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// produce our qbit //
|
||||||
|
//////////////////////
|
||||||
|
StandardProcessTraceQBitProducer producer = new StandardProcessTraceQBitProducer()
|
||||||
|
.withStandardProcessTraceQBitConfig(new StandardProcessTraceQBitConfig()
|
||||||
|
.withTableMetaDataCustomizer((QInstance instance, QTableMetaData table) ->
|
||||||
|
{
|
||||||
|
table.setBackendName(MEMORY_BACKEND_NAME);
|
||||||
|
return (table);
|
||||||
|
})
|
||||||
|
.withIncludeBackendActivityStats(true));
|
||||||
|
|
||||||
|
MetaDataProducerMultiOutput allQBitMetaData = producer.produce(qInstance);
|
||||||
|
allQBitMetaData.addSelfToInstance(qInstance);
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// produce some test tables //
|
||||||
|
// note - nice to be a qbit this too? //
|
||||||
|
////////////////////////////////////////
|
||||||
|
qInstance.addTable(new QTableMetaData()
|
||||||
|
.withName(TABLE_NAME_PERSON)
|
||||||
|
.withBackendName(MEMORY_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withIsEditable(true))
|
||||||
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withIsEditable(true))
|
||||||
|
.withCapability(Capability.QUERY_STATS)
|
||||||
|
);
|
||||||
|
|
||||||
|
qInstance.addTable(new QTableMetaData()
|
||||||
|
.withName(TABLE_NAME_ORDER)
|
||||||
|
.withBackendName(MEMORY_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("orderNo", QFieldType.STRING).withIsEditable(true))
|
||||||
|
.withField(new QFieldMetaData("storeId", QFieldType.INTEGER).withIsEditable(true))
|
||||||
|
.withField(new QFieldMetaData("shipTo", QFieldType.STRING).withIsEditable(true))
|
||||||
|
.withCapability(Capability.QUERY_STATS)
|
||||||
|
);
|
||||||
|
|
||||||
|
qInstance.addProcess(StreamedETLWithFrontendProcess.processMetaDataBuilder()
|
||||||
|
.withName(PROCESS_NAME_PLACE_ORDERS)
|
||||||
|
.withTableName(TABLE_NAME_PERSON)
|
||||||
|
.withSourceTable(TABLE_NAME_PERSON)
|
||||||
|
.withDestinationTable(TABLE_NAME_ORDER)
|
||||||
|
.withExtractStepClass(ExtractViaQueryStep.class)
|
||||||
|
.withTransformStepClass(PlaceOrdersProcessTransformStep.class)
|
||||||
|
.withLoadStepClass(LoadViaInsertStep.class)
|
||||||
|
.getProcessMetaData()
|
||||||
|
.withProcessTracerCodeReference(new QCodeReference(StandardProcessTracer.class))
|
||||||
|
);
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// turn off audits (why on by default??) //
|
||||||
|
///////////////////////////////////////////
|
||||||
|
qInstance.getTables().values().forEach(t -> t.setAuditRules(new QAuditRules().withAuditLevel(AuditLevel.NONE)));
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// create apps //
|
||||||
|
/////////////////
|
||||||
|
qInstance.addApp(new QAppMetaData()
|
||||||
|
.withName("logs")
|
||||||
|
.withIcon(new QIcon("history_edu"))
|
||||||
|
.withSection(StandardProcessTraceQBitProducer.getAppSection(qInstance)));
|
||||||
|
|
||||||
|
qInstance.addApp(new QAppMetaData()
|
||||||
|
.withName("testData")
|
||||||
|
.withIcon(new QIcon("dataset"))
|
||||||
|
.withSection(new QAppSection()
|
||||||
|
.withName("people")
|
||||||
|
.withTables(List.of(TABLE_NAME_PERSON))));
|
||||||
|
|
||||||
|
return qInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* test process transformer - for each input person, creates an output order (to insert)
|
||||||
|
***************************************************************************/
|
||||||
|
public static class PlaceOrdersProcessTransformStep extends AbstractTransformStep
|
||||||
|
{
|
||||||
|
private ProcessSummaryLine okLine = new ProcessSummaryLine(Status.OK)
|
||||||
|
.withMessageSuffix("")
|
||||||
|
.withSingularFutureMessage("will get a new order")
|
||||||
|
.withPluralFutureMessage("will get new orders")
|
||||||
|
.withSingularPastMessage("got a new order")
|
||||||
|
.withPluralPastMessage("got new orders");
|
||||||
|
|
||||||
|
private ProcessSummaryLine errorLine = new ProcessSummaryLine(Status.ERROR)
|
||||||
|
.withMessageSuffix("")
|
||||||
|
.withSingularFutureMessage("will not get a new order")
|
||||||
|
.withPluralFutureMessage("will not get new orders")
|
||||||
|
.withSingularPastMessage("did not get a new order")
|
||||||
|
.withPluralPastMessage("did not get new orders");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public ArrayList<ProcessSummaryLineInterface> getProcessSummary(RunBackendStepOutput runBackendStepOutput, boolean isForResultScreen)
|
||||||
|
{
|
||||||
|
ArrayList<ProcessSummaryLineInterface> rs = new ArrayList<>();
|
||||||
|
okLine.addSelfToListIfAnyCount(rs);
|
||||||
|
errorLine.addSelfToListIfAnyCount(rs);
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void runOnePage(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||||
|
{
|
||||||
|
for(QRecord personRecord : runBackendStepInput.getRecords())
|
||||||
|
{
|
||||||
|
////////////////////////////////////////
|
||||||
|
// don't let Mr. Burns order anything //
|
||||||
|
////////////////////////////////////////
|
||||||
|
if("Burns".equals(personRecord.getValueString("lastName")))
|
||||||
|
{
|
||||||
|
errorLine.incrementCountAndAddPrimaryKey(personRecord.getValue("id"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRecord orderRecord = new QRecord()
|
||||||
|
.withValue("orderNo", UUID.randomUUID().toString())
|
||||||
|
.withValue("shipTo", personRecord.getValueString("firstName") + " " + personRecord.getValueString("lastName"));
|
||||||
|
runBackendStepOutput.addRecord(orderRecord);
|
||||||
|
okLine.incrementCountAndAddPrimaryKey(personRecord.getValue("id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.logging.QCollectingLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for ProcessTraceBackendActivityStatsManager
|
||||||
|
*******************************************************************************/
|
||||||
|
class ProcessTraceBackendActivityStatsManagerTest
|
||||||
|
{
|
||||||
|
ProcessTraceBackendActivityStatsManager.Key key = new ProcessTraceBackendActivityStatsManager.Key("b", "t", "a");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@AfterEach
|
||||||
|
void afterEach()
|
||||||
|
{
|
||||||
|
ProcessTraceBackendActivityStatsManager manager = ProcessTraceBackendActivityStatsManager.getInstance();
|
||||||
|
manager.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testMaxAgeLarger() throws QException
|
||||||
|
{
|
||||||
|
long processTraceId = 1L;
|
||||||
|
QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(ProcessTraceBackendActivityStatsManager.class);
|
||||||
|
|
||||||
|
ProcessTraceBackendActivityStatsManager manager = ProcessTraceBackendActivityStatsManager.getInstance();
|
||||||
|
manager.initProcess(processTraceId);
|
||||||
|
manager.add(processTraceId, key, 1, 2, 3);
|
||||||
|
manager.setCleanupIntervalMillis(10);
|
||||||
|
manager.setCleanupMaxAge(100);
|
||||||
|
SleepUtils.sleep(50, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
QLogger.deactivateCollectingLoggerForClass(ProcessTraceBackendActivityStatsManager.class);
|
||||||
|
assertThat(collectingLogger.getCollectedMessages()).allMatch(clm -> clm.getMessage().contains("\"size\":1"));
|
||||||
|
|
||||||
|
List<ProcessTraceBackendActivityStats> stats = manager.getAndRemoveStats(processTraceId);
|
||||||
|
assertEquals(1, stats.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testMaxAgeSmaller() throws QException
|
||||||
|
{
|
||||||
|
long processTraceId = 2L;
|
||||||
|
QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(ProcessTraceBackendActivityStatsManager.class);
|
||||||
|
|
||||||
|
ProcessTraceBackendActivityStatsManager manager = ProcessTraceBackendActivityStatsManager.getInstance();
|
||||||
|
manager.initProcess(processTraceId);
|
||||||
|
manager.add(processTraceId, key, 1, 2, 3);
|
||||||
|
manager.setCleanupIntervalMillis(5);
|
||||||
|
manager.setCleanupMaxAge(20);
|
||||||
|
// Wait for the scheduled cleanup rather than assuming a shared CI runner
|
||||||
|
// will schedule the background thread within 50 milliseconds.
|
||||||
|
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(2);
|
||||||
|
while(System.nanoTime() < deadline)
|
||||||
|
{
|
||||||
|
var messages = collectingLogger.getCollectedMessages();
|
||||||
|
if(!messages.isEmpty() && messages.get(messages.size() - 1).getMessage().contains("\"size\":0"))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SleepUtils.sleep(5, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
QLogger.deactivateCollectingLoggerForClass(ProcessTraceBackendActivityStatsManager.class);
|
||||||
|
assertThat(collectingLogger.getCollectedMessages()).anyMatch(clm -> clm.getMessage().contains("\"size\":1"));
|
||||||
|
assertThat(collectingLogger.getCollectedMessages()).anyMatch(clm -> clm.getMessage().contains("\"size\":0"));
|
||||||
|
|
||||||
|
List<ProcessTraceBackendActivityStats> stats = manager.getAndRemoveStats(processTraceId);
|
||||||
|
assertEquals(0, stats.size());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// make sure even after a cleanup, we don't fail if we do try to add values for a process //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
manager.add(processTraceId, key, 1, 2, 3);
|
||||||
|
stats = manager.getAndRemoveStats(processTraceId);
|
||||||
|
assertEquals(1, stats.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+176
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qbits.standardprocesstrace.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.BaseTest;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.StandardProcessTraceTestApplication;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTrace;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceBackendActivityStats;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLine;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryLineRecordInt;
|
||||||
|
import com.kingsrook.qbits.standardprocesstrace.model.ProcessTraceSummaryStatusEnum;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.tables.QQQTableTableManager;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for StandardProcessTracer
|
||||||
|
*******************************************************************************/
|
||||||
|
class StandardProcessTracerTest extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test() throws QException
|
||||||
|
{
|
||||||
|
insertHomerMargeAndMrBurns();
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// run process skipping backend steps //
|
||||||
|
////////////////////////////////////////
|
||||||
|
RunProcessInput input = new RunProcessInput();
|
||||||
|
input.setProcessName(StandardProcessTraceTestApplication.PROCESS_NAME_PLACE_ORDERS);
|
||||||
|
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
|
||||||
|
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
|
||||||
|
new RunProcessAction().execute(input);
|
||||||
|
|
||||||
|
baseAssertionsAfterProcess();
|
||||||
|
|
||||||
|
Integer personTableId = QQQTableTableManager.getQQQTableId(QContext.getQInstance(), StandardProcessTraceTestApplication.TABLE_NAME_PERSON);
|
||||||
|
Integer orderTableId = QQQTableTableManager.getQQQTableId(QContext.getQInstance(), StandardProcessTraceTestApplication.TABLE_NAME_ORDER);
|
||||||
|
|
||||||
|
List<QRecord> processTraceBackendActivityStatRecords = QueryAction.execute(ProcessTraceBackendActivityStats.TABLE_NAME, new QQueryFilter());
|
||||||
|
assertThat(processTraceBackendActivityStatRecords)
|
||||||
|
.hasSizeGreaterThanOrEqualTo(2)
|
||||||
|
.anyMatch(r -> r.getValue("qqqTableId").equals(personTableId) && r.getValue("actionName").equals(QueryAction.class.getSimpleName()) && r.getValueInteger("callCount").equals(1) && r.getValueInteger("recordCount").equals(3))
|
||||||
|
.anyMatch(r -> r.getValue("qqqTableId").equals(orderTableId) && r.getValue("actionName").equals(InsertAction.class.getSimpleName()) && r.getValueInteger("callCount").equals(1) && r.getValueInteger("recordCount").equals(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testResumingFrontendProcess() throws QException
|
||||||
|
{
|
||||||
|
insertHomerMargeAndMrBurns();
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// start process - break at preview //
|
||||||
|
//////////////////////////////////////
|
||||||
|
RunProcessInput input = new RunProcessInput();
|
||||||
|
input.setProcessName(StandardProcessTraceTestApplication.PROCESS_NAME_PLACE_ORDERS);
|
||||||
|
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
|
||||||
|
input.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||||
|
RunProcessOutput output = new RunProcessAction().execute(input);
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// continue to execute the process //
|
||||||
|
/////////////////////////////////////
|
||||||
|
input.setProcessUUID(output.getProcessUUID());
|
||||||
|
input.setStartAfterStep(output.getProcessState().getNextStepName().get());
|
||||||
|
new RunProcessAction().execute(input);
|
||||||
|
|
||||||
|
baseAssertionsAfterProcess();
|
||||||
|
|
||||||
|
Integer personTableId = QQQTableTableManager.getQQQTableId(QContext.getQInstance(), StandardProcessTraceTestApplication.TABLE_NAME_PERSON);
|
||||||
|
Integer orderTableId = QQQTableTableManager.getQQQTableId(QContext.getQInstance(), StandardProcessTraceTestApplication.TABLE_NAME_ORDER);
|
||||||
|
|
||||||
|
List<QRecord> processTraceBackendActivityStatRecords = QueryAction.execute(ProcessTraceBackendActivityStats.TABLE_NAME, new QQueryFilter());
|
||||||
|
assertThat(processTraceBackendActivityStatRecords)
|
||||||
|
.hasSizeGreaterThanOrEqualTo(2)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// this time, there'll be 2 calls to the query (for preview, and execute steps), for twice as many records total //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
.anyMatch(r -> r.getValue("qqqTableId").equals(personTableId) && r.getValue("actionName").equals(QueryAction.class.getSimpleName()) && r.getValueInteger("callCount").equals(2) && r.getValueInteger("recordCount").equals(6))
|
||||||
|
.anyMatch(r -> r.getValue("qqqTableId").equals(orderTableId) && r.getValue("actionName").equals(InsertAction.class.getSimpleName()) && r.getValueInteger("callCount").equals(1) && r.getValueInteger("recordCount").equals(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
private static void insertHomerMargeAndMrBurns() throws QException
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// insert 3 people to run through the process. //
|
||||||
|
// the process will insert an order for Homer & Marge, but is hard-coded to make an error for Mr. Burns. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
new InsertAction().execute(new InsertInput(StandardProcessTraceTestApplication.TABLE_NAME_PERSON).withRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 100).withValue("firstName", "Homer").withValue("lastName", "Simpson"),
|
||||||
|
new QRecord().withValue("id", 101).withValue("firstName", "Marge").withValue("lastName", "Simpson"),
|
||||||
|
new QRecord().withValue("id", 102).withValue("firstName", "Mr.").withValue("lastName", "Burns")
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
private static void baseAssertionsAfterProcess() throws QException
|
||||||
|
{
|
||||||
|
List<QRecord> processTraceRecords = QueryAction.execute(ProcessTrace.TABLE_NAME, new QQueryFilter());
|
||||||
|
assertEquals(1, processTraceRecords.size());
|
||||||
|
|
||||||
|
List<QRecord> processTraceSummaryLineRecords = QueryAction.execute(ProcessTraceSummaryLine.TABLE_NAME, new QQueryFilter());
|
||||||
|
assertEquals(2, processTraceSummaryLineRecords.size());
|
||||||
|
|
||||||
|
QRecord okSummaryLineRecord = processTraceSummaryLineRecords.stream().filter(r -> r.getValueString("status").equals(ProcessTraceSummaryStatusEnum.OK.getPossibleValueId())).findFirst().get();
|
||||||
|
assertNotNull(okSummaryLineRecord);
|
||||||
|
assertEquals(2, okSummaryLineRecord.getValueInteger("recordCount"));
|
||||||
|
|
||||||
|
List<QRecord> okRecordInts = QueryAction.execute(ProcessTraceSummaryLineRecordInt.TABLE_NAME, new QQueryFilter(new QFilterCriteria("processTraceSummaryLineId", QCriteriaOperator.EQUALS, okSummaryLineRecord.getValueLong("id"))));
|
||||||
|
assertEquals(2, okRecordInts.size());
|
||||||
|
assertThat(okRecordInts).allMatch(r -> r.getValueInteger("recordId").equals(100) || r.getValueInteger("recordId").equals(101));
|
||||||
|
|
||||||
|
QRecord errorSummaryLineRecord = processTraceSummaryLineRecords.stream().filter(r -> r.getValueString("status").equals(ProcessTraceSummaryStatusEnum.ERROR.getPossibleValueId())).findFirst().get();
|
||||||
|
assertNotNull(errorSummaryLineRecord);
|
||||||
|
assertEquals(1, errorSummaryLineRecord.getValueInteger("recordCount"));
|
||||||
|
|
||||||
|
List<QRecord> errorRecordInts = QueryAction.execute(ProcessTraceSummaryLineRecordInt.TABLE_NAME, new QQueryFilter(new QFilterCriteria("processTraceSummaryLineId", QCriteriaOperator.EQUALS, errorSummaryLineRecord.getValueLong("id"))));
|
||||||
|
assertEquals(1, errorRecordInts.size());
|
||||||
|
assertEquals(102, errorRecordInts.get(0).getValueInteger("recordId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in new issue
Block a user