├── .editorconfig
├── .github
├── dependabot.yml
├── renovate.json
└── workflows
│ ├── backport.yml
│ └── ci-pipeline.yml
├── .gitignore
├── CODE_OF_CONDUCT.MD
├── COPYING-HEADER.txt
├── LICENSE
├── README.md
├── docker
├── application.yaml
├── clickhouse-config.xml
├── clickhouse-users.xml
└── docker-compose.yml
├── how-it-works.jpg
├── pom.xml
├── renovate.json
└── src
├── main
└── java
│ └── io
│ └── zeebe
│ └── clickhouse
│ └── exporter
│ ├── ClickHouseExporter.java
│ ├── ClickHouseExporterClient.java
│ ├── ExporterConfiguration.java
│ └── importer
│ ├── ClickHouseConfig.java
│ ├── ErrorImporter.java
│ ├── IncidentImporter.java
│ ├── JobImporter.java
│ ├── MessageImporter.java
│ ├── MessageSubscriptionImporter.java
│ ├── ProcessImporter.java
│ ├── ProcessInstanceImporter.java
│ ├── SignalSubscriptionImporter.java
│ ├── TimerImporter.java
│ └── VariableImporter.java
└── test
├── java
└── io
│ └── zeebe
│ └── clickhouse
│ └── exporter
│ └── ClickHouseExporterIT.java
└── resources
├── application.yaml
└── logback-test.xml
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_style = space
3 | charset = utf-8
4 | end_of_line = lf
5 | trim_trailing_whitespace = true
6 | insert_final_newline = true
7 |
8 | [*.xml]
9 | indent_size = 2
10 |
11 | [*.html]
12 | indent_size = 2
13 |
14 | [*.md]
15 | indent_size = 2
16 |
17 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "maven" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 |
13 | - package-ecosystem: "github-actions"
14 | directory: "/"
15 | schedule:
16 | interval: "daily"
17 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | { "enabled": false }
2 |
--------------------------------------------------------------------------------
/.github/workflows/backport.yml:
--------------------------------------------------------------------------------
1 | name: Backport labeled merged pull requests
2 | on:
3 | pull_request:
4 | types: [closed]
5 | issue_comment:
6 | types: [created]
7 | jobs:
8 | build:
9 | name: Create backport PRs
10 | runs-on: ubuntu-latest
11 | # Only run when pull request is merged
12 | # or when a comment containing `/backport` is created
13 | if: >
14 | (
15 | github.event_name == 'pull_request' &&
16 | github.event.pull_request.merged
17 | ) || (
18 | github.event_name == 'issue_comment' &&
19 | github.event.issue.pull_request &&
20 | contains(github.event.comment.body, '/backport')
21 | )
22 | steps:
23 | - uses: actions/checkout@v4
24 | - uses: korthout/backport-action@v3
25 |
--------------------------------------------------------------------------------
/.github/workflows/ci-pipeline.yml:
--------------------------------------------------------------------------------
1 | # If this workflow is triggered by a push to $default_branch, it
2 | # deploys a SNAPSHOT
3 | # If this workflow is triggered by publishing a Release, it
4 | # deploys a RELEASE with the selected version
5 | # updates the project version by incrementing the patch version
6 | # commits the version update change to the repository's default branch ($default_branch).
7 | name: Build, test and deploy artifacts with Maven
8 | on:
9 | pull_request: { }
10 | push: { }
11 | workflow_dispatch: { }
12 | release:
13 | types: [ published ]
14 | jobs:
15 | build:
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Cache
20 | uses: actions/cache@v4.1.2
21 | with:
22 | path: ~/.m2/repository
23 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
24 | restore-keys: |
25 | ${{ runner.os }}-maven-
26 | - name: Set up Java environment
27 | uses: actions/setup-java@v4
28 | with:
29 | java-version: 11
30 | distribution: temurin
31 | gpg-private-key: ${{ secrets.MAVEN_CENTRAL_GPG_SIGNING_KEY_SEC }}
32 | gpg-passphrase: MAVEN_CENTRAL_GPG_PASSPHRASE
33 | - name: Build
34 | id: build
35 | run: mvn -B -U -Dsurefire.rerunFailingTestsCount=5 clean install
36 | - name: Archive Test Results on Failure
37 | uses: actions/upload-artifact@v4
38 | if: failure()
39 | with:
40 | name: test-results
41 | path: target/surefire-reports/
42 | retention-days: 7
43 | - name: Publish Unit Test Results
44 | id: publish
45 | uses: EnricoMi/publish-unit-test-result-action@v2
46 | if: failure()
47 | with:
48 | files: target/surefire-reports/*.xml
49 | - if: github.event.release || github.event_name == 'workflow_dispatch'
50 | name: Deploy SNAPSHOT / Release
51 | uses: camunda-community-hub/community-action-maven-release@v1.2.2
52 | with:
53 | release-version: ${{ github.event.release.tag_name }}
54 | release-profile: community-action-maven-release
55 | nexus-usr: ${{ secrets.NEXUS_USR }}
56 | nexus-psw: ${{ secrets.NEXUS_PSW }}
57 | maven-usr: ${{ secrets.MAVEN_CENTRAL_DEPLOYMENT_USR }}
58 | maven-psw: ${{ secrets.MAVEN_CENTRAL_DEPLOYMENT_PSW }}
59 | maven-gpg-passphrase: ${{ secrets.MAVEN_CENTRAL_GPG_SIGNING_KEY_PASSPHRASE }}
60 | github-token: ${{ secrets.GITHUB_TOKEN }}
61 | id: release
62 | - if: github.event.release
63 | name: Attach artifacts to GitHub Release (Release only)
64 | uses: actions/upload-release-asset@v1
65 | env:
66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
67 | with:
68 | upload_url: ${{ github.event.release.upload_url }}
69 | asset_path: ${{ steps.release.outputs.artifacts_archive_path }}
70 | asset_name: ${{ steps.release.outputs.artifacts_archive_path }}
71 | asset_content_type: application/zip
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | pom.xml.tag
3 | pom.xml.releaseBackup
4 | pom.xml.versionsBackup
5 | pom.xml.next
6 | release.properties
7 | dependency-reduced-pom.xml
8 | buildNumber.properties
9 | .mvn/timing.properties
10 | # https://maven.apache.org/wrapper/#usage-without-binary-jar
11 | .mvn/wrapper/maven-wrapper.jar
12 | /.classpath
13 | /.project
14 | /.settings/
15 | /give-me-a-name.iml
16 | /.idea/
17 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.MD:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | ### View the [Camunda Code of Conduct](https://camunda.com/events/code-conduct/) and find ways to report violations.
4 |
--------------------------------------------------------------------------------
/COPYING-HEADER.txt:
--------------------------------------------------------------------------------
1 | Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
2 | one or more contributor license agreements. See the NOTICE file distributed
3 | with this work for additional information regarding copyright ownership.
4 | Licensed under the Zeebe Community License 1.1. You may not use this file
5 | except in compliance with the Zeebe Community License 1.1.
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/camunda-community-hub/community)
2 | [](https://github.com/Camunda-Community-Hub/community/blob/main/extension-lifecycle.md#incubating-)
3 | [](https://opensource.org/licenses/Apache-2.0)
4 |
5 | [](https://github.com/camunda-community-hub/community/blob/main/extension-lifecycle.md#compatiblilty)
6 |
7 | # Zeebe ClickHouse Exporter
8 |
9 | [Exporters](https://docs.camunda.io/docs/next/components/zeebe/technical-concepts/architecture/#exporters) allow you to tap into the Zeebe event stream on a partition and export selected events to other systems. You can filter events, perform transformations, and even trigger side-effects from an exporter.
10 |
11 | Read a two-part series about building Zeebe exporters on the Zeebe blog: [Part One](https://camunda.com/blog/2019/05/exporter-part-1/) | [Part Two](https://camunda.com/blog/2019/06/exporter-part-2/).
12 |
13 | This [Zeebe ClickHouse Exporter](https://github.com/camunda-community-hub/zeebe-clickhouse-exporter) is build on [Zeebe Exporter Demo](https://github.com/jwulf/zeebe-exporter-demo.git) and [ClickHouse Java Libraries](https://github.com/ClickHouse/clickhouse-java.git).
14 |
15 | You can export records from Zeebe to ClickHouse and query data from ClickHouse use you own program language.
16 |
17 | 
18 |
19 |
20 | ## About ClickHouse
21 |
22 | [ClickHouse](https://clickhouse.com/clickhouse) is a column-oriented database that enables its users to generate powerful analytics, using SQL queries, in real-time.
23 |
24 | ClickHouse is an Open Source OLAP database management system.
25 |
26 | ClickHouse runs on ClickHouse Cloud or any Linux, FreeBSD, or macOS system with x86_64, AArch64, or PowerPC64LE CPU architecture.
27 |
28 | [ClickHouse Quick Start](https://clickhouse.com/docs/en/getting-started/quick-start/) follow these steps to get up and running with ClickHouse.
29 |
30 | [ClickHouse Java Libraries](https://github.com/ClickHouse/clickhouse-java) for connecting to ClickHouse and processing data in various formats. Java client is async, lightweight, and low-overhead library for ClickHouse
31 |
32 | [ClickHouse Asynchronous Inserts](https://clickhouse.com/docs/en/cloud/bestpractices/asynchronous-inserts) inserting data into ClickHouse in large batches is a best practice.
33 |
34 | ## Deploy the Exporter
35 |
36 | 1. Build the exporter, using `mvn package`.
37 | 2. Copy the resulting `zeebe-clickhouse-exporter-1.0-SNAPSHOT.jar` file to the `exporters` directory of your Zeebe broker.
38 | 3. Edit the `application.yaml` file, and add an entry for the exporter, you can change
39 |
40 | * the ClickHouse jdbc url `chUrl`
41 | * the ClickHouse user `chUser`
42 | * the ClickHouse password `chPassword`
43 |
44 | ```
45 | exporters:
46 | clickhouse:
47 | className: io.zeebe.clickhouse.exporter.ClickHouseExporter
48 | jarPath: exporters/zeebe-clickhouse-exporter-1.0-SNAPSHOT.jar
49 | args:
50 | chUrl: jdbc:ch://127.0.0.1:8123/default
51 | chUser: default
52 | chPassword: clickhouse123
53 | ```
54 | The values can be overridden by environment variables.
55 |
56 | * set `chUrl` with `ZEEBE_CLICKHOUSE_URL` (e.g. `export ZEEBE_CLICKHOUSE_URL=jdbc:ch://127.0.0.1:8123/default`)
57 | * set `chUser` with `ZEEBE_CLICKHOUSE_USER` (e.g. `export ZEEBE_CLICKHOUSE_USER=default`)
58 | * set `chPassword` with `ZEEBE_CLICKHOUSE_PASSWORD` (e.g. `export ZEEBE_CLICKHOUSE_PASSWORD=""`)
59 |
60 |
61 | ## ClickHouse Zeebe Tables
62 |
63 | ```
64 | chk :) show tables;
65 |
66 | SHOW TABLES
67 |
68 | Query id: e18a6412-c726-48d2-b73b-6e78c0af3b12
69 |
70 | ┌─name─────────────────┐
71 | │ CLICKHOUSE_CONFIG │
72 | │ ELEMENT_INSTANCE │
73 | │ ERROR │
74 | │ INCIDENT │
75 | │ JOB │
76 | │ MESSAGE │
77 | │ MESSAGE_SUBSCRIPTION │
78 | │ PROCESS │
79 | │ PROCESS_INSTANCE │
80 | │ TIMER │
81 | │ VARIABLE │
82 | └──────────────────────┘
83 |
84 | 11 rows in set. Elapsed: 0.002 sec.
85 |
86 | chk :)
87 | ```
88 |
89 | ## ClickHouse Query Process Records
90 | ```
91 | chk :) select KEY_,BPMN_PROCESS_ID_,RESOURCE_NAME_,TIMESTAMP_,PARTITION_ID_,POSITION_,VERSION_ from PROCESS;
92 |
93 | SELECT
94 | KEY_,
95 | BPMN_PROCESS_ID_,
96 | RESOURCE_NAME_,
97 | TIMESTAMP_,
98 | PARTITION_ID_,
99 | POSITION_,
100 | VERSION_
101 | FROM PROCESS
102 |
103 | Query id: 3d27fd6a-87fb-4891-b27d-8b445ac7bc64
104 |
105 | ┌─────────────KEY_─┬─BPMN_PROCESS_ID_─┬─RESOURCE_NAME_───────┬──────────────TIMESTAMP_─┬─PARTITION_ID_─┬─POSITION_─┬─VERSION_─┐
106 | │ 2251799813685986 │ Process_0k1nnh5 │ Process_0k1nnh5.bpmn │ 2023-03-11 12:56:00.614 │ 1 │ 1900 │ 4 │
107 | │ 2251799813686688 │ Process_0k1nnh5 │ Process_0k1nnh5.bpmn │ 2023-03-11 13:22:36.327 │ 1 │ 3704 │ 5 │
108 | │ 2251799813687390 │ Process_0k1nnh5 │ Process_0k1nnh5.bpmn │ 2023-03-11 13:45:48.440 │ 1 │ 5508 │ 6 │
109 | │ 2251799813687393 │ Process_0k1nnh5 │ Process_0k1nnh5.bpmn │ 2023-03-11 13:49:07.744 │ 1 │ 5513 │ 7 │
110 | │ 2251799813687395 │ Process_0k1nnh5 │ Process_0k1nnh5.bpmn │ 2023-03-11 13:50:22.217 │ 1 │ 5518 │ 8 │
111 | └──────────────────┴──────────────────┴──────────────────────┴─────────────────────────┴───────────────┴───────────┴──────────┘
112 |
113 | 5 rows in set. Elapsed: 0.003 sec.
114 |
115 | chk :)
116 | ```
117 |
118 | ## ClickHouse Query Process Instance Records
119 | ```
120 | chk :) select * from PROCESS_INSTANCE limit 10;
121 |
122 | SELECT *
123 | FROM PROCESS_INSTANCE
124 | LIMIT 10
125 |
126 | Query id: 790c13cc-5066-49c0-9068-4e6e610b8cf0
127 |
128 | ┌─────────────KEY_─┬─BPMN_PROCESS_ID_─┬─PROCESS_DEFINITION_KEY_─┬──────────────────START_─┬─END_─┬─PARTITION_ID_─┬─VERSION_─┬─STATE_─┬─PARENT_PROCESS_INSTANCE_KEY_─┬─PARENT_ELEMENT_INSTANCE_KEY_─┐
129 | │ 2251799813685989 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:03.649 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
130 | │ 2251799813685996 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:06.651 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
131 | │ 2251799813686003 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:09.632 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
132 | │ 2251799813686010 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:12.639 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
133 | │ 2251799813686017 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:15.643 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
134 | │ 2251799813686024 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:18.623 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
135 | │ 2251799813686031 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:21.621 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
136 | │ 2251799813686038 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:24.651 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
137 | │ 2251799813686045 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:27.649 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
138 | │ 2251799813686052 │ Process_0k1nnh5 │ 2251799813685986 │ 2023-03-11 12:56:30.649 │ ᴺᵁᴸᴸ │ 1 │ 4 │ Active │ -1 │ -1 │
139 | └──────────────────┴──────────────────┴─────────────────────────┴─────────────────────────┴──────┴───────────────┴──────────┴────────┴──────────────────────────────┴──────────────────────────────┘
140 |
141 | 10 rows in set. Elapsed: 0.003 sec.
142 |
143 | chk :)
144 | ```
145 |
146 | ## ClickHouse Query Element Instance Records
147 | ```
148 | chk :) select * from ELEMENT_INSTANCE where PROCESS_INSTANCE_KEY_=2251799813689134 order by TIMESTAMP_ asc;
149 |
150 | SELECT *
151 | FROM ELEMENT_INSTANCE
152 | WHERE PROCESS_INSTANCE_KEY_ = 2251799813689134
153 | ORDER BY TIMESTAMP_ ASC
154 |
155 | Query id: ebbffa4f-c188-47b1-99a4-3d18e84645bb
156 |
157 | ┌─ID──────┬─────────────KEY_─┬─BPMN_PROCESS_ID_─┬─PROCESS_DEFINITION_KEY_─┬──────────────TIMESTAMP_─┬─INTENT_─────────────┬─PARTITION_ID_─┬─POSITION_─┬─PROCESS_INSTANCE_KEY_─┬──FLOW_SCOPE_KEY_─┬─ELEMENT_ID_──────┬─BPMN_ELEMENT_TYPE_─┐
158 | │ 1-9991 │ 2251799813689134 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.349 │ ELEMENT_ACTIVATING │ 1 │ 9991 │ 2251799813689134 │ -1 │ Process_1udqk7z │ PROCESS │
159 | │ 1-9992 │ 2251799813689134 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.349 │ ELEMENT_ACTIVATED │ 1 │ 9992 │ 2251799813689134 │ -1 │ Process_1udqk7z │ PROCESS │
160 | │ 1-9994 │ 2251799813689137 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.349 │ ELEMENT_ACTIVATING │ 1 │ 9994 │ 2251799813689134 │ 2251799813689134 │ StartEvent_1 │ START_EVENT │
161 | │ 1-9995 │ 2251799813689137 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.349 │ ELEMENT_ACTIVATED │ 1 │ 9995 │ 2251799813689134 │ 2251799813689134 │ StartEvent_1 │ START_EVENT │
162 | │ 1-9997 │ 2251799813689137 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.352 │ ELEMENT_COMPLETING │ 1 │ 9997 │ 2251799813689134 │ 2251799813689134 │ StartEvent_1 │ START_EVENT │
163 | │ 1-9998 │ 2251799813689137 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.352 │ ELEMENT_COMPLETED │ 1 │ 9998 │ 2251799813689134 │ 2251799813689134 │ StartEvent_1 │ START_EVENT │
164 | │ 1-9999 │ 2251799813689138 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.352 │ SEQUENCE_FLOW_TAKEN │ 1 │ 9999 │ 2251799813689134 │ 2251799813689134 │ Flow_0j9gwbw │ SEQUENCE_FLOW │
165 | │ 1-10001 │ 2251799813689139 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.356 │ ELEMENT_ACTIVATING │ 1 │ 10001 │ 2251799813689134 │ 2251799813689134 │ Activity_0v39lo1 │ USER_TASK │
166 | │ 1-10003 │ 2251799813689139 │ Process_1udqk7z │ 2251799813685323 │ 2023-03-12 11:29:13.356 │ ELEMENT_ACTIVATED │ 1 │ 10003 │ 2251799813689134 │ 2251799813689134 │ Activity_0v39lo1 │ USER_TASK │
167 | └─────────┴──────────────────┴──────────────────┴─────────────────────────┴─────────────────────────┴─────────────────────┴───────────────┴───────────┴───────────────────────┴──────────────────┴──────────────────┴────────────────────┘
168 |
169 | 9 rows in set. Elapsed: 0.044 sec. Processed 9.09 thousand rows, 1.43 MB (204.70 thousand rows/s., 32.24 MB/s.)
170 |
171 | chk :)
172 | ```
173 |
174 | ## ClickHouse Query Timer Records
175 | ```
176 | chk :) select * from TIMER limit 10;
177 |
178 | SELECT *
179 | FROM TIMER
180 | LIMIT 10
181 |
182 | Query id: 96d218f8-7628-4a98-978a-d018bc420b8f
183 |
184 | ┌─────────────KEY_─┬─STATE_────┬─REPETITIONS─┬──────────────TIMESTAMP_─┬───────────────DUE_DATE_─┬─PROCESS_INSTANCE_KEY_─┬─PROCESS_DEFINITION_KEY_─┬─ELEMENT_INSTANCE_KEY_─┬─TARGET_ELEMENT_ID_─┐
185 | │ 2251799813685987 │ triggered │ 100 │ 2023-03-11 12:56:03.649 │ 2023-03-11 12:56:03.614 │ 2251799813685989 │ 2251799813685986 │ -1 │ StartEvent_1 │
186 | │ 2251799813685991 │ triggered │ 99 │ 2023-03-11 12:56:06.651 │ 2023-03-11 12:56:06.614 │ 2251799813685996 │ 2251799813685986 │ -1 │ StartEvent_1 │
187 | │ 2251799813685998 │ triggered │ 98 │ 2023-03-11 12:56:09.632 │ 2023-03-11 12:56:09.614 │ 2251799813686003 │ 2251799813685986 │ -1 │ StartEvent_1 │
188 | │ 2251799813686005 │ triggered │ 97 │ 2023-03-11 12:56:12.639 │ 2023-03-11 12:56:12.614 │ 2251799813686010 │ 2251799813685986 │ -1 │ StartEvent_1 │
189 | │ 2251799813686012 │ triggered │ 96 │ 2023-03-11 12:56:15.643 │ 2023-03-11 12:56:15.614 │ 2251799813686017 │ 2251799813685986 │ -1 │ StartEvent_1 │
190 | │ 2251799813686019 │ triggered │ 95 │ 2023-03-11 12:56:18.623 │ 2023-03-11 12:56:18.614 │ 2251799813686024 │ 2251799813685986 │ -1 │ StartEvent_1 │
191 | │ 2251799813686026 │ triggered │ 94 │ 2023-03-11 12:56:21.621 │ 2023-03-11 12:56:21.614 │ 2251799813686031 │ 2251799813685986 │ -1 │ StartEvent_1 │
192 | │ 2251799813686033 │ triggered │ 93 │ 2023-03-11 12:56:24.651 │ 2023-03-11 12:56:24.614 │ 2251799813686038 │ 2251799813685986 │ -1 │ StartEvent_1 │
193 | │ 2251799813686040 │ triggered │ 92 │ 2023-03-11 12:56:27.649 │ 2023-03-11 12:56:27.614 │ 2251799813686045 │ 2251799813685986 │ -1 │ StartEvent_1 │
194 | │ 2251799813686047 │ triggered │ 91 │ 2023-03-11 12:56:30.649 │ 2023-03-11 12:56:30.614 │ 2251799813686052 │ 2251799813685986 │ -1 │ StartEvent_1 │
195 | └──────────────────┴───────────┴─────────────┴─────────────────────────┴─────────────────────────┴───────────────────────┴─────────────────────────┴───────────────────────┴────────────────────┘
196 |
197 | 10 rows in set. Elapsed: 0.003 sec.
198 |
199 | chk :)
200 | ```
201 | ## ClickHouse Query Job Records
202 | ```
203 | chk :) select * from JOB limit 10;
204 |
205 | SELECT *
206 | FROM JOB
207 | LIMIT 10
208 |
209 | Query id: b123ba7f-b552-4dba-9d66-9d30a9478a6d
210 |
211 | ┌─────────────KEY_─┬─BPMN_PROCESS_ID_─┬─ELEMENT_ID_──────┬─WORKER_─┬─JOB_TYPE_─────────────────┬─STATE_──┬─RETRIES_─┬──────────────────START_─┬─END_─┬─PROCESS_INSTANCE_KEY_─┬─ELEMENT_INSTANCE_KEY_─┬─PROCESS_DEFINITION_KEY_─┐
212 | │ 2251799813685995 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:03.649 │ ᴺᵁᴸᴸ │ 2251799813685989 │ 2251799813685994 │ 2251799813685986 │
213 | │ 2251799813686002 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:06.651 │ ᴺᵁᴸᴸ │ 2251799813685996 │ 2251799813686001 │ 2251799813685986 │
214 | │ 2251799813686009 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:09.632 │ ᴺᵁᴸᴸ │ 2251799813686003 │ 2251799813686008 │ 2251799813685986 │
215 | │ 2251799813686016 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:12.639 │ ᴺᵁᴸᴸ │ 2251799813686010 │ 2251799813686015 │ 2251799813685986 │
216 | │ 2251799813686023 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:15.643 │ ᴺᵁᴸᴸ │ 2251799813686017 │ 2251799813686022 │ 2251799813685986 │
217 | │ 2251799813686030 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:18.623 │ ᴺᵁᴸᴸ │ 2251799813686024 │ 2251799813686029 │ 2251799813685986 │
218 | │ 2251799813686037 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:21.621 │ ᴺᵁᴸᴸ │ 2251799813686031 │ 2251799813686036 │ 2251799813685986 │
219 | │ 2251799813686044 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:24.651 │ ᴺᵁᴸᴸ │ 2251799813686038 │ 2251799813686043 │ 2251799813685986 │
220 | │ 2251799813686051 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:27.649 │ ᴺᵁᴸᴸ │ 2251799813686045 │ 2251799813686050 │ 2251799813685986 │
221 | │ 2251799813686058 │ Process_0k1nnh5 │ Activity_0fhkw5l │ │ io.camunda.zeebe:userTask │ created │ 1 │ 2023-03-11 12:56:30.649 │ ᴺᵁᴸᴸ │ 2251799813686052 │ 2251799813686057 │ 2251799813685986 │
222 | └──────────────────┴──────────────────┴──────────────────┴─────────┴───────────────────────────┴─────────┴──────────┴─────────────────────────┴──────┴───────────────────────┴───────────────────────┴─────────────────────────┘
223 |
224 | 10 rows in set. Elapsed: 0.002 sec.
225 |
226 | chk :)
227 | ```
228 |
229 | ## ClickHouse Query Message Subscription Records
230 | ```
231 | chk :) select * from MESSAGE_SUBSCRIPTION order by TIMESTAMP_ asc;
232 |
233 | SELECT *
234 | FROM MESSAGE_SUBSCRIPTION
235 | ORDER BY TIMESTAMP_ ASC
236 |
237 | Query id: 3da1ad48-3023-4e58-a17b-a671a87e7228
238 |
239 | ┌─ID_──────────────────────────────────┬─MESSAGE_NAME_───┬─MESSAGE_KEY_─┬──────────────TIMESTAMP_─┬─STATE_──┬─PROCESS_INSTANCE_KEY_─┬─ELEMENT_INSTANCE_KEY_─┬─PROCESS_DEFINITION_KEY_─┬─CORRELATION_KEY_─┬─TARGET_FLOW_NODE_ID_─┐
240 | │ afd4a50b-0053-4e19-a5f5-74aac0013b04 │ Message_0l9728h │ -1 │ 2023-03-12 04:01:18.081 │ created │ -1 │ -1 │ 2251799813687398 │ │ StartEvent_1 │
241 | │ e77d6a70-e93c-4521-88aa-3d1e4de46a95 │ Message_0l9728h │ -1 │ 2023-03-12 04:01:33.286 │ deleted │ -1 │ -1 │ 2251799813687398 │ │ StartEvent_1 │
242 | │ fb7e88a0-79e3-42bd-8a30-d0bf9a887b6e │ Message_0l9728h │ -1 │ 2023-03-12 04:01:33.286 │ created │ -1 │ -1 │ 2251799813687401 │ │ StartEvent_1 │
243 | └──────────────────────────────────────┴─────────────────┴──────────────┴─────────────────────────┴─────────┴───────────────────────┴───────────────────────┴─────────────────────────┴──────────────────┴──────────────────────┘
244 |
245 | 3 rows in set. Elapsed: 0.005 sec.
246 |
247 | chk :)
248 |
249 | ```
250 |
251 | ## ClickHouse Query Message Records
252 | ```
253 | chk :) select * from MESSAGE order by TIMESTAMP_ asc;
254 |
255 | SELECT *
256 | FROM MESSAGE
257 | ORDER BY TIMESTAMP_ ASC
258 |
259 | Query id: 4263bdf6-585e-4209-ab46-f25a2b0820d1
260 |
261 | ┌─────────────KEY_─┬─NAME_───────────┬──────────────TIMESTAMP_─┬─STATE_────┬─CORRELATION_KEY_─┬─MESSAGE_ID_─┬─PAYLOAD_────────┐
262 | │ 2251799813687404 │ Message_0l9728h │ 2023-03-12 04:14:37.390 │ published │ 123 │ │ {x=1, y=2} │
263 | │ 2251799813687415 │ Message_0l9728h │ 2023-03-12 04:15:39.281 │ published │ 9876467 │ │ {x=1, y=2} │
264 | │ 2251799813687426 │ Message_0l9728h │ 2023-03-12 04:17:54.630 │ published │ 23223423 │ │ {x=11, y=29} │
265 | │ 2251799813687437 │ Message_0l9728h │ 2023-03-12 04:21:17.489 │ published │ 23233 │ │ {x=111, y=39} │
266 | │ 2251799813687448 │ Message_0l9728h │ 2023-03-12 04:22:19.181 │ published │ 238868823 │ │ {x=1121, y=339} │
267 | └──────────────────┴─────────────────┴─────────────────────────┴───────────┴──────────────────┴─────────────┴─────────────────┘
268 |
269 | 5 rows in set. Elapsed: 0.006 sec.
270 |
271 | chk :)
272 |
273 | ```
274 |
275 | ## ClickHouse Query Variable Records
276 | ```
277 | chk :) select * from VARIABLE limit 5;
278 |
279 | SELECT *
280 | FROM VARIABLE
281 | LIMIT 5
282 |
283 | Query id: 43b29497-c340-4ee5-beed-769e56f46d62
284 |
285 | ┌─ID─────┬─NAME_─┬─VALUE_─┬──────────────TIMESTAMP_─┬─PARTITION_ID_─┬─POSITION_─┬─PROCESS_INSTANCE_KEY_─┬─PROCESS_DEFINITION_KEY_─┬───────SCOPE_KEY_─┬─STATE_──┐
286 | │ 1-5544 │ x │ "1" │ 2023-03-12 04:14:37.390 │ 1 │ 5544 │ 2251799813687405 │ 2251799813687401 │ 2251799813687407 │ created │
287 | │ 1-5545 │ y │ "2" │ 2023-03-12 04:14:37.390 │ 1 │ 5545 │ 2251799813687405 │ 2251799813687401 │ 2251799813687407 │ created │
288 | │ 1-5548 │ y │ "2" │ 2023-03-12 04:14:37.390 │ 1 │ 5548 │ 2251799813687405 │ 2251799813687401 │ 2251799813687405 │ created │
289 | │ 1-5549 │ x │ "1" │ 2023-03-12 04:14:37.390 │ 1 │ 5549 │ 2251799813687405 │ 2251799813687401 │ 2251799813687405 │ created │
290 | │ 1-5566 │ x │ "1" │ 2023-03-12 04:15:39.281 │ 1 │ 5566 │ 2251799813687416 │ 2251799813687401 │ 2251799813687418 │ created │
291 | └────────┴───────┴────────┴─────────────────────────┴───────────────┴───────────┴───────────────────────┴─────────────────────────┴──────────────────┴─────────┘
292 |
293 | 5 rows in set. Elapsed: 0.004 sec.
294 |
295 | chk :)
296 | ```
297 |
298 | ## ClickHouse Query Signal Subscription Records
299 | ```
300 | chk :) select * from SIGNAL_SUBSCRIPTION order by PROCESS_DEFINITION_KEY_ asc,TIMESTAMP_ asc;
301 |
302 | SELECT *
303 | FROM SIGNAL_SUBSCRIPTION
304 | ORDER BY
305 | PROCESS_DEFINITION_KEY_ ASC,
306 | TIMESTAMP_ ASC
307 |
308 | Query id: bda77cac-a74a-4123-9f52-f6c14e682c5e
309 |
310 | ┌─ID_──────────────────────────────────┬─SIGNAL_NAME_───┬──────────────TIMESTAMP_─┬─STATE_──┬─CATCH_ELEMENT_INSTANCE_KEY_─┬─PROCESS_DEFINITION_KEY_─┬─BPMN_PROCESS_ID_─┬─CATCH_EVENT_ID_─┐
311 | │ 7f43d9eb-6fb9-49f0-90b2-4920560413d4 │ Signal_1mcst4h │ 2023-03-12 14:52:33.197 │ deleted │ -1 │ 2251799813692399 │ Process_1udqk7z │ StartEvent_1 │
312 | │ 2307850b-9505-49aa-a368-4f9431d36c5f │ Signal_1mcst4h │ 2023-03-12 14:52:33.197 │ created │ -1 │ 2251799813692405 │ Process_1udqk7z │ StartEvent_1 │
313 | │ 7d723b2e-56bd-4d1b-9b07-dafe0ad95e11 │ Signal_3h5lmif │ 2023-03-12 14:54:03.718 │ created │ -1 │ 2251799813692408 │ Process_0k1nnh5 │ StartEvent_1 │
314 | │ c8603d0a-7935-4bb4-8570-970aa2d0c5a2 │ Signal_3h5lmif │ 2023-03-12 14:54:21.340 │ deleted │ -1 │ 2251799813692408 │ Process_0k1nnh5 │ StartEvent_1 │
315 | │ eee80948-95d6-402a-9ea6-4657d5aaf1f2 │ Signal_3h5lmif │ 2023-03-12 14:54:21.340 │ created │ -1 │ 2251799813692411 │ Process_0k1nnh5 │ StartEvent_1 │
316 | └──────────────────────────────────────┴────────────────┴─────────────────────────┴─────────┴─────────────────────────────┴─────────────────────────┴──────────────────┴─────────────────┘
317 |
318 | 5 rows in set. Elapsed: 0.003 sec.
319 |
320 | chk :)
321 | ```
322 |
--------------------------------------------------------------------------------
/docker/application.yaml:
--------------------------------------------------------------------------------
1 | zeebe:
2 | broker:
3 | exporters:
4 | clickhouse:
5 | className: io.zeebe.clickhouse.exporter.ClickHouseExporter
6 | jarPath: exporters/zeebe-clickhouse-exporter-1.0-SNAPSHOT.jar
7 |
8 |
--------------------------------------------------------------------------------
/docker/clickhouse-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
25 | trace
26 | /var/log/clickhouse-server/clickhouse-server.log
27 | /var/log/clickhouse-server/clickhouse-server.err.log
28 |
31 | 1000M
32 | 10
33 |
34 |
35 |
40 |
45 |
46 |
51 |
63 |
70 |
71 |
72 |
73 |
74 |
75 |
93 |
94 |
97 |
98 |
99 |
103 | 8123
104 |
105 |
112 | 9000
113 |
114 |
117 | 9004
118 |
119 |
122 | 9005
123 |
124 |
128 |
129 |
130 |
134 |
135 |
136 |
140 |
141 |
142 |
149 | 9009
150 |
151 |
156 |
157 |
158 |
163 |
164 |
167 |
168 |
172 |
176 |
177 |
187 | ::
188 |
189 |
190 |
191 |
192 |
193 |
194 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
208 |
209 |
210 |
211 |
212 | 4096
213 |
214 |
215 | 3
216 |
217 |
218 |
219 |
220 | false
221 |
222 |
223 | /path/to/ssl_cert_file
224 | /path/to/ssl_key_file
225 |
226 |
227 | false
228 |
229 |
230 | /path/to/ssl_ca_cert_file
231 |
232 |
234 | none
235 |
236 |
237 | 0
238 |
239 |
240 | -1
241 | -1
242 |
243 |
244 | false
245 |
246 |
247 |
248 |
249 |
250 |
251 |
253 |
258 |
259 | none
260 | true
261 | true
262 | sslv2,sslv3
263 | true
264 |
265 |
266 |
267 | true
268 | true
269 | sslv2,sslv3
270 | true
271 |
272 |
273 |
274 | RejectCertificateHandler
275 |
276 |
277 |
278 |
279 |
280 |
283 |
284 |
289 | 0
290 |
291 |
292 | 100
293 |
294 |
305 | 0
306 |
307 |
313 |
314 | 10000
315 |
316 |
318 |
319 |
320 |
322 | 0.9
323 |
324 |
328 | 4194304
329 |
330 |
336 | 0
337 |
338 |
340 |
341 |
342 |
351 | 8589934592
352 |
353 |
357 | 5368709120
358 |
359 |
360 |
376 | 1000
377 |
378 |
379 | 134217728
380 |
381 |
382 | 10000
383 |
384 |
385 | /var/lib/clickhouse/
386 |
387 |
388 |
438 |
439 |
440 |
441 | /var/lib/clickhouse/tmp/
442 |
443 |
444 |
445 | `
446 |
447 |
456 |
457 |
458 |
459 | /var/lib/clickhouse/user_files/
460 |
461 |
462 |
463 |
528 |
529 |
530 |
550 |
551 |
552 |
553 |
554 |
555 | users.xml
556 |
557 |
558 |
559 | /var/lib/clickhouse/access/
560 |
561 |
562 |
618 |
619 |
620 |
621 |
625 | false
626 |
627 |
629 | false
630 |
631 |
637 | false
638 |
639 |
642 | false
643 |
644 |
645 |
646 | default
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
658 |
659 |
660 |
661 | default
662 |
663 |
675 | Asia/Shanghai
676 |
677 |
680 |
681 |
682 |
686 | true
687 |
688 |
689 | false
690 |
691 | ' | sed -e 's|.*>\(.*\)<.*|\1|')
698 | wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge_$PKG_VER-1_all.deb
699 | apt install --no-install-recommends -f ./clickhouse-jdbc-bridge_$PKG_VER-1_all.deb
700 | clickhouse-jdbc-bridge &
701 |
702 | * [CentOS/RHEL]
703 | export MVN_URL=https://repo1.maven.org/maven2/com/clickhouse/clickhouse-jdbc-bridge/
704 | export PKG_VER=$(curl -sL $MVN_URL/maven-metadata.xml | grep '' | sed -e 's|.*>\(.*\)<.*|\1|')
705 | wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm
706 | yum localinstall -y clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm
707 | clickhouse-jdbc-bridge &
708 |
709 | Please refer to https://github.com/ClickHouse/clickhouse-jdbc-bridge#usage for more information.
710 | ]]>
711 |
717 |
718 |
721 |
722 |
723 |
724 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 | localhost
753 | 9000
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 | false
762 |
763 | 127.0.0.1
764 | 9000
765 |
766 |
767 | 127.0.0.2
768 | 9000
769 |
770 |
771 | 127.0.0.3
772 | 9000
773 |
774 |
775 |
790 |
791 |
792 |
793 |
794 | localhost
795 | 9000
796 |
797 |
798 |
799 |
800 | localhost
801 | 9000
802 |
803 |
804 |
805 |
806 |
807 |
808 | 127.0.0.1
809 | 9000
810 |
811 |
812 |
813 |
814 | 127.0.0.2
815 | 9000
816 |
817 |
818 |
819 |
820 |
821 | true
822 |
823 | 127.0.0.1
824 | 9000
825 |
826 |
827 |
828 | true
829 |
830 | 127.0.0.2
831 | 9000
832 |
833 |
834 |
835 |
836 |
837 |
838 | localhost
839 | 9440
840 | 1
841 |
842 |
843 |
844 |
845 |
846 |
847 | localhost
848 | 9000
849 |
850 |
851 |
852 |
853 | localhost
854 | 1
855 |
856 |
857 |
858 |
859 |
860 |
863 |
864 |
874 |
875 |
879 |
880 |
881 |
885 |
886 |
891 |
892 |
908 |
909 |
914 |
920 |
921 |
922 |
923 | 3600
924 |
925 |
926 |
927 | 3600
928 |
929 |
930 | 60
931 |
932 |
933 |
941 |
968 |
969 |
970 |
978 |
989 |
990 |
991 |
992 |
996 | system
997 |
998 |
1006 | toYYYYMM(event_date)
1007 |
1016 |
1017 |
1020 |
1021 |
1022 | 7500
1023 |
1024 |
1025 |
1027 |
1028 | system
1029 |
1030 |
1031 | toYYYYMM(event_date)
1032 | 7500
1033 |
1034 |
1035 |
1037 |
1038 | system
1039 |
1040 | toYYYYMM(event_date)
1041 | 7500
1042 |
1043 |
1044 |
1046 |
1047 | system
1048 |
1049 | toYYYYMM(event_date)
1050 | 7500
1051 |
1052 |
1053 |
1055 |
1056 | system
1057 |
1058 | toYYYYMM(event_date)
1059 | 7500
1060 |
1061 |
1062 |
1072 |
1073 |
1074 |
1075 | system
1076 |
1077 | 7500
1078 | 1000
1079 |
1080 |
1081 |
1085 |
1086 | system
1087 |
1088 |
1092 | 7000
1093 |
1094 |
1095 |
1098 |
1099 |
1109 |
1110 | engine MergeTree
1111 | partition by toYYYYMM(finish_date)
1112 | order by (finish_date, finish_time_us, trace_id)
1113 |
1114 | system
1115 |
1116 | 7500
1117 |
1118 |
1119 |
1120 |
1122 |
1123 | system
1124 |
1125 |
1126 |
1127 | 1000
1128 |
1129 |
1130 |
1134 |
1141 |
1142 |
1143 |
1144 | system
1145 |
1146 |
1147 | toYYYYMM(event_date)
1148 | 7500
1149 |
1150 |
1151 |
1152 |
1158 |
1159 |
1162 |
1163 |
1164 |
1167 | *_dictionary.xml
1168 |
1169 |
1170 | *_function.xml
1171 |
1172 |
1175 |
1189 |
1190 |
1195 |
1196 |
1197 |
1198 |
1199 |
1200 |
1201 |
1202 |
1203 |
1204 |
1205 |
1206 |
1207 |
1208 |
1209 |
1210 |
1211 |
1212 |
1213 |
1214 |
1215 |
1216 |
1217 |
1218 |
1220 |
1221 |
1222 | /clickhouse/task_queue/ddl
1223 |
1224 |
1225 |
1226 |
1227 |
1228 |
1229 |
1230 |
1233 |
1234 |
1235 |
1236 |
1237 |
1238 |
1239 |
1240 |
1241 |
1242 |
1243 |
1244 |
1245 |
1250 |
1251 |
1258 |
1259 |
1260 |
1261 |
1262 |
1263 |
1264 | click_cost
1265 | any
1266 |
1267 | 0
1268 | 3600
1269 |
1270 |
1271 | 86400
1272 | 60
1273 |
1274 |
1275 |
1276 | max
1277 |
1278 | 0
1279 | 60
1280 |
1281 |
1282 | 3600
1283 | 300
1284 |
1285 |
1286 | 86400
1287 | 3600
1288 |
1289 |
1290 |
1291 |
1292 |
1295 | /var/lib/clickhouse/format_schemas/
1296 |
1297 |
1303 |
1304 |
1305 | hide encrypt/decrypt arguments
1306 | ((?:aes_)?(?:encrypt|decrypt)(?:_mysql)?)\s*\(\s*(?:'(?:\\'|.)+'|.*?)\s*\)
1307 |
1310 | \1(???)
1311 |
1312 |
1313 |
1314 |
1357 |
1358 |
1359 |
1360 |
1361 |
1362 | false
1363 |
1364 | false
1365 |
1366 |
1367 | https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277
1368 |
1369 |
1370 |
1371 |
1372 |
1373 |
1374 |
1395 |
1396 |
1397 |
1401 |
1402 |
1410 |
1411 |
--------------------------------------------------------------------------------
/docker/clickhouse-users.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 | random
18 |
19 |
20 |
21 |
22 | 1
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
65 | clickhouse123
66 |
67 |
87 |
88 | ::/0
89 |
90 |
91 |
92 | default
93 |
94 |
95 | default
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | 3600
110 |
111 |
112 | 0
113 | 0
114 | 0
115 | 0
116 | 0
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 |
3 | networks:
4 | zeebe_network:
5 | driver: bridge
6 |
7 | services:
8 | clickhouse:
9 | container_name: clickhouse
10 | image: clickhouse/clickhouse-server:24.11.1.2557
11 | ulimits:
12 | nofile:
13 | soft: 262144
14 | hard: 262144
15 | ports:
16 | - "8123:8123"
17 | - "19600:9600"
18 | volumes:
19 | - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
20 | - ./clickhouse-users.xml:/etc/clickhouse-server/users.xml
21 | healthcheck:
22 | test: [ "CMD-SHELL", "curl -f http://localhost:8123/ | grep -q Ok" ]
23 | interval: 30s
24 | timeout: 5s
25 | retries: 3
26 | start_period: 30s
27 | networks:
28 | - zeebe_network
29 |
30 | zeebe:
31 | container_name: zeebe_broker
32 | image: camunda/zeebe:8.6.5
33 | environment:
34 | - ZEEBE_LOG_LEVEL=debug
35 | - ZEEBE_CLICKHOUSE_URL=jdbc:ch://clickhouse/default
36 | - ZEEBE_CLICKHOUSE_USER=default
37 | - ZEEBE_CLICKHOUSE_PASSWORD=clickhouse123
38 | ports:
39 | - "26500:26500"
40 | - "9600:9600"
41 | volumes:
42 | - ../target/zeebe-clickhouse-exporter-1.0-SNAPSHOT.jar:/usr/local/zeebe/exporters/zeebe-clickhouse-exporter-1.0-SNAPSHOT.jar
43 | - ./application.yaml:/usr/local/zeebe/config/application.yaml
44 | networks:
45 | - zeebe_network
46 | depends_on:
47 | - clickhouse
48 |
--------------------------------------------------------------------------------
/how-it-works.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/camunda-community-hub/zeebe-clickhouse-exporter/5f01980bb6f243b2aee43ccc231266c8b6d82346/how-it-works.jpg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | io.zeebe.clickhouse
5 | zeebe-clickhouse-exporter
6 | jar
7 | 1.0-SNAPSHOT
8 | zeebe-clickhouse-exporter
9 |
10 |
11 | org.camunda.community
12 | community-hub-release-parent
13 | 1.4.4
14 |
15 |
16 |
17 |
18 |
19 | Zeebe Community License v1.1
20 | https://zeebe.io/legal/zeebe-community-license-1.1
21 |
22 |
23 |
24 |
25 |
26 | UTF-8
27 | 17
28 |
29 | https://artifacts.camunda.com/artifactory/zeebe-io-snapshots/
30 |
31 | https://artifacts.camunda.com/artifactory/zeebe-io/
32 |
33 |
34 |
35 |
36 | ${maven.multiModuleProjectDirectory}/COPYING-HEADER.txt
37 |
38 |
39 | 8.6.5
40 | 2.20.0
41 | 5.11.3
42 | 3.26.3
43 | 1.20.4
44 | 3.6.5
45 | 4.2.2
46 | 10.20.2
47 | 0.28.1
48 | 0.6.5
49 | 2.17.0
50 | 3.17.0
51 |
52 |
53 | 1.24
54 | 3.7.1
55 | 3.13.0
56 | 3.5.0
57 | 3.4.0
58 | 3.1.2
59 | 3.5.0
60 | 3.5.2
61 | 2.24
62 | 3.2.7
63 | 3.11.1
64 | 4.6
65 | 0.6.1
66 | 1.0.6
67 | 0.15.0
68 | 3.5.2
69 |
70 |
71 | 1.6.1
72 |
73 |
74 | -Xdoclint:none
75 |
76 |
82 | false
83 | ${skipChecks}
84 | ${skipChecks}
85 | ${skipChecks}
86 | ${skipChecks}
87 | ${skipChecks}
88 | ${skipChecks}
89 |
90 |
91 |
92 |
93 |
94 | io.camunda
95 | zeebe-bom
96 | ${version.zeebe}
97 | import
98 | pom
99 |
100 |
101 | org.junit
102 | junit-bom
103 | ${version.junit}
104 | pom
105 | import
106 |
107 |
108 | org.testcontainers
109 | testcontainers-bom
110 | ${version.testcontainers}
111 | pom
112 | import
113 |
114 |
115 |
116 |
117 |
118 | io.camunda
119 | zeebe-exporter-api
120 | provided
121 |
122 |
123 |
124 | com.clickhouse
125 | clickhouse-jdbc
126 | ${version.clickhouse-jdbc}
127 | http
128 |
129 |
130 | *
131 | *
132 |
133 |
134 |
135 |
136 | commons-io
137 | commons-io
138 | ${version.commons-io}
139 |
140 |
141 | org.apache.commons
142 | commons-lang3
143 | ${version.commons-lang3}
144 |
145 |
146 |
147 |
148 | org.testcontainers
149 | testcontainers
150 | test
151 |
152 |
153 | org.testcontainers
154 | clickhouse
155 | test
156 |
157 |
158 | io.zeebe
159 | zeebe-test-container
160 | ${version.zeebe-test-container}
161 | test
162 |
163 |
164 | org.testcontainers
165 | junit-jupiter
166 | test
167 |
168 |
169 | org.junit.jupiter
170 | junit-jupiter-api
171 | test
172 |
173 |
174 | org.assertj
175 | assertj-core
176 | ${versin.assertj}
177 | test
178 |
179 |
180 | org.awaitility
181 | awaitility
182 | ${version.awaitility}
183 | test
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | org.apache.maven.plugins
193 | maven-compiler-plugin
194 | ${plugin.version.compiler}
195 |
196 |
197 |
198 |
199 | org.apache.maven.plugins
200 | maven-javadoc-plugin
201 | ${plugin.version.javadoc}
202 |
203 | ${version.java}
204 |
205 |
206 |
207 |
208 |
209 | com.mycila
210 | license-maven-plugin
211 | ${plugin.version.license}
212 |
213 |
214 |
215 | camunda services GmbH
216 | info@camunda.com
217 |
218 |
219 | **/*.java
220 |
221 |
222 | SLASHSTAR_STYLE
223 |
224 |
225 |
226 |
227 | add-license
228 | compile
229 |
230 | format
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | org.apache.maven.plugins
239 | maven-checkstyle-plugin
240 | ${plugin.version.checkstyle}
241 |
242 |
243 |
244 | io.camunda
245 | zeebe-build-tools
246 | ${version.zeebe}
247 |
248 |
249 | com.puppycrawl.tools
250 | checkstyle
251 | ${version.checkstyle}
252 |
253 |
254 |
255 | check/.checkstyle.xml
256 | true
257 | UTF-8
258 | true
259 |
260 | ${project.build.sourceDirectory}
261 | ${project.build.testSourceDirectory}
262 |
263 |
264 |
265 |
266 | validate-java
267 | validate
268 |
269 | check
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 | org.apache.maven.plugins
280 | maven-surefire-plugin
281 | ${plugin.version.surefire}
282 |
283 | false
284 | false
285 | true
286 |
287 |
288 | junit.jupiter.execution.parallel.enabled = true
289 | junit.jupiter.execution.parallel.mode.default = same_thread
290 | junit.jupiter.execution.parallel.config.strategy = dynamic
291 | junit.jupiter.execution.parallel.config.dynamic.factor = 2
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 | org.apache.maven.plugins
300 | maven-failsafe-plugin
301 | ${plugin.version.failsafe}
302 |
303 | false
304 | false
305 | true
306 |
307 |
308 | junit.jupiter.execution.parallel.enabled = true
309 | junit.jupiter.execution.parallel.mode.default = same_thread
310 | junit.jupiter.execution.parallel.config.strategy = dynamic
311 | junit.jupiter.execution.parallel.config.dynamic.factor = 2
312 |
313 |
314 |
315 |
316 |
317 |
318 | integration-test
319 | verify
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 | com.spotify.fmt
328 | fmt-maven-plugin
329 | ${plugin.version.fmt}
330 |
331 |
332 |
333 | format
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 | org.apache.maven.plugins
342 | maven-assembly-plugin
343 | ${plugin.version.assembly}
344 |
345 |
346 |
347 |
348 | org.apache.maven.plugins
349 | maven-enforcer-plugin
350 | ${plugin.version.enforcer}
351 |
352 |
353 | enforce-dependency-convergence
354 |
355 | enforce
356 |
357 |
358 |
359 |
360 |
361 |
362 | [11,)
363 |
364 |
365 | [3.6,)
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 | org.apache.maven.plugins
376 | maven-clean-plugin
377 | ${plugin.version.clean}
378 |
379 |
380 |
381 |
382 | org.revapi
383 | revapi-maven-plugin
384 | ${plugin.version.revapi}
385 |
386 |
387 | org.revapi
388 | revapi-java
389 | ${version.revapi}
390 |
391 |
392 |
393 |
394 | verify
395 | check
396 |
397 | check
398 |
399 |
400 |
401 |
402 | true
403 | true
404 | true
405 |
406 |
407 |
408 | ${maven.multiModuleProjectDirectory}/revapi.json
409 |
410 |
411 |
412 |
413 |
414 |
415 | org.codehaus.mojo
416 | animal-sniffer-maven-plugin
417 | ${plugin.version.animal-sniffer}
418 |
419 |
420 |
421 |
422 |
423 |
424 | org.apache.maven.plugins
425 | maven-assembly-plugin
426 |
427 |
428 | jar-with-dependencies
429 |
430 | ${project.build.directory}
431 |
432 |
433 |
434 | assemble-all
435 | package
436 |
437 | single
438 |
439 |
440 |
441 | assemble-for-jib
442 | package
443 |
444 | single
445 |
446 |
447 | ${project.build.directory}/jib
448 | ${project.artifactId}
449 |
450 |
451 |
452 |
453 |
455 |
456 | org.apache.maven.plugins
457 | maven-dependency-plugin
458 |
459 |
460 | copy
461 | pre-integration-test
462 |
463 | copy
464 |
465 |
466 |
467 |
468 | io.zeebe.clickhouse
469 | zeebe-clickhouse-exporter
470 | ${project.version}
471 | jar
472 | jar-with-dependencies
473 | ${project.basedir}/src/test/resources
474 | zeebe-clickhouse-exporter.jar
475 |
476 |
477 | false
478 | true
479 |
480 |
481 |
482 |
483 |
484 |
485 | org.apache.maven.plugins
486 | maven-compiler-plugin
487 |
488 |
489 |
490 | com.mycila
491 | license-maven-plugin
492 |
493 |
494 |
495 | org.apache.maven.plugins
496 | maven-checkstyle-plugin
497 |
498 |
499 |
500 | org.apache.maven.plugins
501 | maven-surefire-plugin
502 |
503 |
504 |
505 | com.spotify.fmt
506 | fmt-maven-plugin
507 |
508 |
509 |
510 | org.apache.maven.plugins
511 | maven-enforcer-plugin
512 |
513 |
514 |
515 | org.apache.maven.plugins
516 | maven-clean-plugin
517 |
518 |
519 |
520 |
521 |
522 | community-action-maven-release
523 |
524 | true
525 | true
526 |
527 |
528 |
529 |
530 |
531 | org.apache.maven.plugins
532 | maven-gpg-plugin
533 | ${plugin.version.gpg}
534 |
535 |
536 | sign-artifacts
537 | verify
538 |
539 | sign
540 |
541 |
542 |
543 |
544 |
545 |
546 | --pinentry-mode
547 | loopback
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 | zeebe
559 | Zeebe Repository
560 | https://artifacts.camunda.com/artifactory/zeebe-io/
561 |
562 | true
563 |
564 |
565 | false
566 |
567 |
568 |
569 |
570 | zeebe-snapshots
571 | Zeebe Snapshot Repository
572 | https://artifacts.camunda.com/artifactory/zeebe-io-snapshots/
573 |
574 | false
575 |
576 |
577 | true
578 |
579 |
580 |
581 |
582 |
583 | https://github.com/camunda-community-hub/zeebe-clickhouse-exporter
584 | scm:git:git@github.com:camunda-community-hub/zeebe-clickhouse-exporter.git
585 | scm:git:git@github.com:camunda-community-hub/zeebe-clickhouse-exporter.git
586 |
587 | HEAD
588 |
589 |
590 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/ClickHouseExporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter;
9 |
10 | import io.camunda.zeebe.exporter.api.Exporter;
11 | import io.camunda.zeebe.exporter.api.context.Context;
12 | import io.camunda.zeebe.exporter.api.context.Controller;
13 | import io.camunda.zeebe.protocol.record.Record;
14 | import org.slf4j.Logger;
15 |
16 | public class ClickHouseExporter implements Exporter {
17 |
18 | private Logger logger;
19 | private Controller controller;
20 |
21 | private ExporterConfiguration configuration;
22 | private ClickHouseExporterClient client;
23 |
24 | @Override
25 | public void configure(final Context context) {
26 | logger = context.getLogger();
27 | configuration = context.getConfiguration().instantiate(ExporterConfiguration.class);
28 | logger.info("Exporter configured with {}", configuration);
29 | }
30 |
31 | @Override
32 | public void open(final Controller controller) {
33 | this.controller = controller;
34 | client = createClient();
35 | logger.info("Exporter opened");
36 | }
37 |
38 | @Override
39 | public void close() {}
40 |
41 | @Override
42 | public void export(final Record> record) {
43 | final long lastPosition = record.getPosition();
44 | client.insert(record, lastPosition);
45 | controller.updateLastExportedRecordPosition(lastPosition);
46 | }
47 |
48 | protected ClickHouseExporterClient createClient() {
49 | return new ClickHouseExporterClient(configuration, logger);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/ClickHouseExporterClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter;
9 |
10 | import static io.zeebe.clickhouse.exporter.importer.ClickHouseConfig.*;
11 |
12 | import io.camunda.zeebe.protocol.record.Record;
13 | import io.camunda.zeebe.protocol.record.RecordType;
14 | import io.camunda.zeebe.protocol.record.ValueType;
15 | import io.zeebe.clickhouse.exporter.importer.*;
16 | import java.sql.SQLException;
17 | import org.slf4j.Logger;
18 |
19 | public class ClickHouseExporterClient {
20 |
21 | private final String elementInstanceTable = "ELEMENT_INSTANCE";
22 | private final String clickHouseConfigTable = "CLICKHOUSE_CONFIG";
23 |
24 | private final ExporterConfiguration configuration;
25 |
26 | private final Logger logger;
27 | private long cfgPosition = -1;
28 |
29 | ClickHouseExporterClient(final ExporterConfiguration configuration, final Logger logger) {
30 | this.configuration = configuration;
31 | this.logger = logger;
32 | logger.info("configuration--------------->" + configuration.toString());
33 | try {
34 | // 初始化配置表
35 | createClickHouseConfigTable(
36 | configuration.getChUrl(),
37 | configuration.getChUser(),
38 | configuration.getChPassword(),
39 | clickHouseConfigTable);
40 | // 检查是否有初始化配置信息
41 | final long i =
42 | queryClickHouseConfig(
43 | configuration.getChUrl(),
44 | configuration.getChUser(),
45 | configuration.getChPassword(),
46 | clickHouseConfigTable);
47 |
48 | if (i <= 0L) {
49 | // 执行初始化
50 | initClickHouseConfigTable(
51 | configuration.getChUrl(),
52 | configuration.getChUser(),
53 | configuration.getChPassword(),
54 | clickHouseConfigTable);
55 | } else {
56 | cfgPosition = i;
57 | }
58 | // 创建流程定义信息表
59 | createProcessTable(
60 | configuration.getChUrl(),
61 | configuration.getChUser(),
62 | configuration.getChPassword(),
63 | ValueType.PROCESS.name());
64 | // 创建流程实例表
65 | createProcessInstanceTable(
66 | configuration.getChUrl(),
67 | configuration.getChUser(),
68 | configuration.getChPassword(),
69 | ValueType.PROCESS_INSTANCE.name());
70 | // 创建任务实例表
71 | createElementInstanceTable(
72 | configuration.getChUrl(),
73 | configuration.getChUser(),
74 | configuration.getChPassword(),
75 | elementInstanceTable);
76 | // 创建调度表
77 | createJobTable(
78 | configuration.getChUrl(),
79 | configuration.getChUser(),
80 | configuration.getChPassword(),
81 | ValueType.JOB.name());
82 | // 创建流程变量表
83 | createVariableTable(
84 | configuration.getChUrl(),
85 | configuration.getChUser(),
86 | configuration.getChPassword(),
87 | ValueType.VARIABLE.name());
88 | // 创建事件表
89 | createIncidentTable(
90 | configuration.getChUrl(),
91 | configuration.getChUser(),
92 | configuration.getChPassword(),
93 | ValueType.INCIDENT.name());
94 | // 创建定时器表
95 | createTimerTable(
96 | configuration.getChUrl(),
97 | configuration.getChUser(),
98 | configuration.getChPassword(),
99 | ValueType.TIMER.name());
100 | // 创建异常表
101 | createErrorTable(
102 | configuration.getChUrl(),
103 | configuration.getChUser(),
104 | configuration.getChPassword(),
105 | ValueType.ERROR.name());
106 | // 创建消息表
107 | createMessageTable(
108 | configuration.getChUrl(),
109 | configuration.getChUser(),
110 | configuration.getChPassword(),
111 | ValueType.MESSAGE.name());
112 | // 创建消息订阅表
113 | createMessageSubscriptionTable(
114 | configuration.getChUrl(),
115 | configuration.getChUser(),
116 | configuration.getChPassword(),
117 | ValueType.MESSAGE_SUBSCRIPTION.name());
118 | // 创建信号订阅表
119 | createSignalSubscriptionTable(
120 | configuration.getChUrl(),
121 | configuration.getChUser(),
122 | configuration.getChPassword(),
123 | ValueType.SIGNAL_SUBSCRIPTION.name());
124 |
125 | } catch (final SQLException e) {
126 | e.printStackTrace();
127 | }
128 | }
129 |
130 | /** 执行数据导出 * */
131 | public void insert(final Record> record, final long lastPosition) {
132 | if ((lastPosition > cfgPosition || cfgPosition == -1L)
133 | && RecordType.EVENT.name().equals(record.getRecordType().name())) {
134 |
135 | logger.info(
136 | String.format("------%s---------->%s", record.getValueType().name(), record.toJson()));
137 | // 流程定义信息
138 | if (ValueType.PROCESS.name().equals(record.getValueType().name())) {
139 | try {
140 |
141 | ProcessImporter.batchProcessInsert(
142 | configuration.getChUrl(),
143 | configuration.getChUser(),
144 | configuration.getChPassword(),
145 | ValueType.PROCESS.name(),
146 | record);
147 | // 更新记录位置
148 | update(lastPosition);
149 | } catch (final SQLException e) {
150 | e.printStackTrace();
151 | }
152 | }
153 | // 流程实例信息 & 任务实例信息
154 | if (ValueType.PROCESS_INSTANCE.name().equals(record.getValueType().name())) {
155 | try {
156 |
157 | // 流程实例信息
158 | ProcessInstanceImporter.batchProcessInstanceInsertOrUpdate(
159 | configuration.getChUrl(),
160 | configuration.getChUser(),
161 | configuration.getChPassword(),
162 | ValueType.PROCESS_INSTANCE.name(),
163 | record);
164 |
165 | // 任务实例信息
166 | ProcessInstanceImporter.batchElementInstanceInsert(
167 | configuration.getChUrl(),
168 | configuration.getChUser(),
169 | configuration.getChPassword(),
170 | elementInstanceTable,
171 | record);
172 | // 更新记录位置
173 | update(lastPosition);
174 | } catch (final SQLException e) {
175 | e.printStackTrace();
176 | }
177 | }
178 |
179 | // 调度信息
180 | if (ValueType.JOB.name().equals(record.getValueType().name())) {
181 | try {
182 |
183 | JobImporter.batchJobInsertOrUpdate(
184 | configuration.getChUrl(),
185 | configuration.getChUser(),
186 | configuration.getChPassword(),
187 | ValueType.JOB.name(),
188 | record);
189 | // 更新记录位置
190 | update(lastPosition);
191 | } catch (final SQLException e) {
192 | e.printStackTrace();
193 | }
194 | }
195 | // 流程变量信息
196 | if (ValueType.VARIABLE.name().equals(record.getValueType().name())) {
197 | try {
198 |
199 | VariableImporter.batchVariableInsert(
200 | configuration.getChUrl(),
201 | configuration.getChUser(),
202 | configuration.getChPassword(),
203 | ValueType.VARIABLE.name(),
204 | record);
205 | // 更新记录位置
206 | update(lastPosition);
207 | } catch (final SQLException e) {
208 | e.printStackTrace();
209 | }
210 | }
211 | // 事件信息
212 | if (ValueType.INCIDENT.name().equals(record.getValueType().name())) {
213 | try {
214 |
215 | IncidentImporter.batchIncidentInsertOrUpdate(
216 | configuration.getChUrl(),
217 | configuration.getChUser(),
218 | configuration.getChPassword(),
219 | ValueType.INCIDENT.name(),
220 | record);
221 | // 更新记录位置
222 | update(lastPosition);
223 | } catch (final SQLException e) {
224 | e.printStackTrace();
225 | }
226 | }
227 | // 定时器信息
228 | if (ValueType.TIMER.name().equals(record.getValueType().name())) {
229 | try {
230 |
231 | TimerImporter.batchTimerInsert(
232 | configuration.getChUrl(),
233 | configuration.getChUser(),
234 | configuration.getChPassword(),
235 | ValueType.TIMER.name(),
236 | record);
237 | // 更新记录位置
238 | update(lastPosition);
239 | } catch (final SQLException e) {
240 | e.printStackTrace();
241 | }
242 | }
243 | // 异常记录信息
244 | if (ValueType.ERROR.name().equals(record.getValueType().name())) {
245 | try {
246 |
247 | ErrorImporter.batchErrorInsert(
248 | configuration.getChUrl(),
249 | configuration.getChUser(),
250 | configuration.getChPassword(),
251 | ValueType.ERROR.name(),
252 | record);
253 | // 更新记录位置
254 | update(lastPosition);
255 | } catch (final SQLException e) {
256 | e.printStackTrace();
257 | }
258 | }
259 | // 消息记录信息
260 | if (ValueType.MESSAGE.name().equals(record.getValueType().name())) {
261 | try {
262 |
263 | MessageImporter.batchMessageInsert(
264 | configuration.getChUrl(),
265 | configuration.getChUser(),
266 | configuration.getChPassword(),
267 | ValueType.MESSAGE.name(),
268 | record);
269 | // 更新记录位置
270 | update(lastPosition);
271 | } catch (final SQLException e) {
272 | e.printStackTrace();
273 | }
274 | }
275 | // 消息订阅记录信息
276 | if (ValueType.MESSAGE_SUBSCRIPTION.name().equals(record.getValueType().name())) {
277 | try {
278 |
279 | MessageSubscriptionImporter.batchMessageSubscriptionInsert(
280 | configuration.getChUrl(),
281 | configuration.getChUser(),
282 | configuration.getChPassword(),
283 | ValueType.MESSAGE_SUBSCRIPTION.name(),
284 | record);
285 | // 更新记录位置
286 | update(lastPosition);
287 | } catch (final SQLException e) {
288 | e.printStackTrace();
289 | }
290 | }
291 | // 消息启动记录信息
292 | if (ValueType.MESSAGE_START_EVENT_SUBSCRIPTION.name().equals(record.getValueType().name())) {
293 | try {
294 |
295 | MessageSubscriptionImporter.batchMessageStartEventSubscriptionInsert(
296 | configuration.getChUrl(),
297 | configuration.getChUser(),
298 | configuration.getChPassword(),
299 | ValueType.MESSAGE_SUBSCRIPTION.name(),
300 | record);
301 | // 更新记录位置
302 | update(lastPosition);
303 | } catch (final SQLException e) {
304 | e.printStackTrace();
305 | }
306 | }
307 | // 信号启动记录信息
308 | if (ValueType.SIGNAL_SUBSCRIPTION.name().equals(record.getValueType().name())) {
309 | try {
310 |
311 | SignalSubscriptionImporter.batchSignalSubscriptionInsert(
312 | configuration.getChUrl(),
313 | configuration.getChUser(),
314 | configuration.getChPassword(),
315 | ValueType.SIGNAL_SUBSCRIPTION.name(),
316 | record);
317 | // 更新记录位置
318 | update(lastPosition);
319 | } catch (final SQLException e) {
320 | e.printStackTrace();
321 | }
322 | }
323 | }
324 | }
325 |
326 | // 更新记录位置
327 | public void update(final long lastPosition) {
328 | try {
329 | updateClickHouseConfigTable(
330 | configuration.getChUrl(),
331 | configuration.getChUser(),
332 | configuration.getChPassword(),
333 | clickHouseConfigTable,
334 | lastPosition);
335 | } catch (final SQLException e) {
336 | e.printStackTrace();
337 | }
338 | }
339 | }
340 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/ExporterConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter;
9 |
10 | import java.util.Optional;
11 |
12 | public class ExporterConfiguration {
13 | private static final String ENV_PREFIX = "ZEEBE_CLICKHOUSE_";
14 | private final String chUrl = "jdbc:ch://127.0.0.1:8123/default";
15 | private final String chUser = "default";
16 | private final String chPassword = "";
17 |
18 | public String getChUrl() {
19 | return getEnv("URL").orElse(chUrl);
20 | }
21 |
22 | public String getChUser() {
23 | return getEnv("USER").orElse(chUser);
24 | }
25 |
26 | public String getChPassword() {
27 | return getEnv("PASSWORD").orElse(chPassword);
28 | }
29 |
30 | private Optional getEnv(final String name) {
31 | return Optional.ofNullable(System.getenv(ENV_PREFIX + name));
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "ExporterConfiguration{"
37 | + "chUrl='"
38 | + chUrl
39 | + '\''
40 | + ", chUser='"
41 | + chUser
42 | + '\''
43 | + ", chPassword='"
44 | + chPassword
45 | + '\''
46 | + '}';
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/ClickHouseConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import java.sql.*;
11 |
12 | public class ClickHouseConfig {
13 |
14 | public static void createClickHouseConfigTable(
15 | final String url, final String user, final String password, final String table)
16 | throws SQLException {
17 | try (final Connection conn = DriverManager.getConnection(url, user, password);
18 | final Statement stmt = conn.createStatement()) {
19 | stmt.execute(
20 | String.format(
21 | "create table if not exists %1$s (KEY_ String,POSITION_ Int64) "
22 | + " engine = MergeTree() ORDER BY KEY_",
23 | table));
24 | }
25 | }
26 |
27 | public static void initClickHouseConfigTable(
28 | final String url, final String user, final String password, final String table)
29 | throws SQLException {
30 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
31 | final String sql = String.format("insert into %1$s values(?, ?)", table);
32 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
33 | ps.setString(1, "cfg");
34 | ps.setLong(2, -1);
35 | ps.execute();
36 | }
37 | }
38 | }
39 |
40 | public static void updateClickHouseConfigTable(
41 | final String url,
42 | final String user,
43 | final String password,
44 | final String table,
45 | final long lastPosition)
46 | throws SQLException {
47 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
48 | final String sql =
49 | String.format("alter table %1$s update POSITION_ = ? where KEY_ = ?", table);
50 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
51 | ps.setLong(1, lastPosition);
52 |
53 | ps.setString(2, "cfg");
54 | ps.execute();
55 | }
56 | }
57 | }
58 |
59 | public static long queryClickHouseConfig(
60 | final String url, final String user, final String password, final String table)
61 | throws SQLException {
62 | try (final Connection conn = DriverManager.getConnection(url, user, password);
63 | final Statement stmt = conn.createStatement();
64 | final ResultSet rs = stmt.executeQuery("select * from " + table)) {
65 | long count = 0;
66 | long cfgposition = -1L;
67 | while (rs.next()) {
68 | count++;
69 | cfgposition = rs.getLong("POSITION_");
70 | }
71 | if (count > 0) {
72 | count = cfgposition;
73 | }
74 | return count;
75 | }
76 | }
77 |
78 | public static void createProcessTable(
79 | final String url, final String user, final String password, final String table)
80 | throws SQLException {
81 | try (final Connection conn = DriverManager.getConnection(url, user, password);
82 | final Statement stmt = conn.createStatement()) {
83 | stmt.execute(
84 | String.format(
85 | "create table if not exists %1$s (KEY_ UInt64,BPMN_PROCESS_ID_ String, RESOURCE_NAME_ String,"
86 | + " TIMESTAMP_ DateTime64(3), PARTITION_ID_ UInt16, POSITION_ UInt64,VERSION_ UInt16,RESOURCE_ String)"
87 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY KEY_",
88 | table));
89 | }
90 | }
91 |
92 | public static void createProcessInstanceTable(
93 | final String url, final String user, final String password, final String table)
94 | throws SQLException {
95 | try (final Connection conn = DriverManager.getConnection(url, user, password);
96 | final Statement stmt = conn.createStatement()) {
97 | stmt.execute(
98 | String.format(
99 | "create table if not exists %1$s (KEY_ UInt64,BPMN_PROCESS_ID_ String,"
100 | + " PROCESS_DEFINITION_KEY_ UInt64, START_ DateTime64(3), "
101 | + " END_ Nullable(DateTime64(3)),PARTITION_ID_ UInt16,"
102 | + " VERSION_ UInt16,STATE_ String, PARENT_PROCESS_INSTANCE_KEY_ Int64,"
103 | + " PARENT_ELEMENT_INSTANCE_KEY_ Int64)"
104 | + " engine = ReplacingMergeTree(START_) PARTITION BY toYYYYMM(START_) ORDER BY KEY_",
105 | table));
106 | }
107 | }
108 |
109 | public static void createErrorTable(
110 | final String url, final String user, final String password, final String table)
111 | throws SQLException {
112 | try (final Connection conn = DriverManager.getConnection(url, user, password);
113 | final Statement stmt = conn.createStatement()) {
114 | stmt.execute(
115 | String.format(
116 | "create table if not exists %1$s (POSITION_ UInt64,ERROR_EVENT_POSITION_ UInt64,"
117 | + " TIMESTAMP_ DateTime64(3),"
118 | + " PROCESS_INSTANCE_KEY_ UInt64,EXCEPTION_MESSAGE_ String, STACKTRACE_ String) "
119 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY POSITION_",
120 | table));
121 | }
122 | }
123 |
124 | public static void createTimerTable(
125 | final String url, final String user, final String password, final String table)
126 | throws SQLException {
127 | try (final Connection conn = DriverManager.getConnection(url, user, password);
128 | final Statement stmt = conn.createStatement()) {
129 | stmt.execute(
130 | String.format(
131 | "create table if not exists %1$s (KEY_ UInt64,STATE_ String, REPETITIONS Int16,"
132 | + " TIMESTAMP_ DateTime64(3),DUE_DATE_ DateTime64(3),"
133 | + " PROCESS_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ UInt64,"
134 | + " ELEMENT_INSTANCE_KEY_ Int64, TARGET_ELEMENT_ID_ String) "
135 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY KEY_",
136 | table));
137 | }
138 | }
139 |
140 | public static void createMessageTable(
141 | final String url, final String user, final String password, final String table)
142 | throws SQLException {
143 | try (final Connection conn = DriverManager.getConnection(url, user, password);
144 | final Statement stmt = conn.createStatement()) {
145 | stmt.execute(
146 | String.format(
147 | "create table if not exists %1$s (KEY_ UInt64,NAME_ String,"
148 | + " TIMESTAMP_ DateTime64(3),STATE_ String,"
149 | + " CORRELATION_KEY_ String,MESSAGE_ID_ String, PAYLOAD_ String) "
150 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY KEY_",
151 | table));
152 | }
153 | }
154 |
155 | public static void createMessageSubscriptionTable(
156 | final String url, final String user, final String password, final String table)
157 | throws SQLException {
158 | try (final Connection conn = DriverManager.getConnection(url, user, password);
159 | final Statement stmt = conn.createStatement()) {
160 | stmt.execute(
161 | String.format(
162 | "create table if not exists %1$s (ID_ String,MESSAGE_NAME_ String,MESSAGE_KEY_ Int64,"
163 | + " TIMESTAMP_ DateTime64(3),STATE_ String,PROCESS_INSTANCE_KEY_ Int64,"
164 | + " ELEMENT_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ Int64,"
165 | + " CORRELATION_KEY_ Nullable(String),TARGET_FLOW_NODE_ID_ Nullable(String)) "
166 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY ID_",
167 | table));
168 | }
169 | }
170 |
171 | public static void createElementInstanceTable(
172 | final String url, final String user, final String password, final String table)
173 | throws SQLException {
174 | try (final Connection conn = DriverManager.getConnection(url, user, password);
175 | final Statement stmt = conn.createStatement()) {
176 | stmt.execute(
177 | String.format(
178 | "create table if not exists %1$s (ID String,KEY_ UInt64,BPMN_PROCESS_ID_ String,"
179 | + " PROCESS_DEFINITION_KEY_ UInt64, TIMESTAMP_ DateTime64(3), "
180 | + " INTENT_ String,PARTITION_ID_ UInt16,"
181 | + " POSITION_ UInt64, PROCESS_INSTANCE_KEY_ UInt64,"
182 | + " FLOW_SCOPE_KEY_ Int64,ELEMENT_ID_ String,BPMN_ELEMENT_TYPE_ String)"
183 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY (ID,INTENT_)",
184 | table));
185 | }
186 | }
187 |
188 | public static void createJobTable(
189 | final String url, final String user, final String password, final String table)
190 | throws SQLException {
191 | try (final Connection conn = DriverManager.getConnection(url, user, password);
192 | final Statement stmt = conn.createStatement()) {
193 | stmt.execute(
194 | String.format(
195 | "create table if not exists %1$s (KEY_ UInt64,BPMN_PROCESS_ID_ String, ELEMENT_ID_ String,"
196 | + " WORKER_ String, JOB_TYPE_ String, STATE_ String, RETRIES_ UInt8, "
197 | + " START_ DateTime64(3),END_ Nullable(DateTime64(3)), PROCESS_INSTANCE_KEY_ UInt64,"
198 | + " ELEMENT_INSTANCE_KEY_ UInt64, PROCESS_DEFINITION_KEY_ UInt64)"
199 | + " engine = ReplacingMergeTree(START_) PARTITION BY toYYYYMM(START_) ORDER BY KEY_",
200 | table));
201 | }
202 | }
203 |
204 | public static void createVariableTable(
205 | final String url, final String user, final String password, final String table)
206 | throws SQLException {
207 | try (final Connection conn = DriverManager.getConnection(url, user, password);
208 | final Statement stmt = conn.createStatement()) {
209 | stmt.execute(
210 | String.format(
211 | "create table if not exists %1$s (ID String,NAME_ String, VALUE_ String,"
212 | + " TIMESTAMP_ DateTime64(3), PARTITION_ID_ UInt16, POSITION_ UInt64,"
213 | + " PROCESS_INSTANCE_KEY_ UInt64,PROCESS_DEFINITION_KEY_ UInt64,"
214 | + " SCOPE_KEY_ Int64, STATE_ String) "
215 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY (PARTITION_ID_,POSITION_)",
216 | table));
217 | }
218 | }
219 |
220 | public static void createIncidentTable(
221 | final String url, final String user, final String password, final String table)
222 | throws SQLException {
223 | try (final Connection conn = DriverManager.getConnection(url, user, password);
224 | final Statement stmt = conn.createStatement()) {
225 | stmt.execute(
226 | String.format(
227 | "create table if not exists %1$s (KEY_ UInt64,BPMN_PROCESS_ID_ String, ERROR_MSG_ String,"
228 | + " ERROR_TYPE_ String, "
229 | + " CREATED_ DateTime64(3),RESOLVED_ Nullable(DateTime64(3)), "
230 | + " PROCESS_INSTANCE_KEY_ UInt64, ELEMENT_INSTANCE_KEY_ UInt64,JOB_KEY_ UInt64,"
231 | + " PROCESS_DEFINITION_KEY_ UInt64)"
232 | + " engine = ReplacingMergeTree(CREATED_) PARTITION BY toYYYYMM(CREATED_) ORDER BY KEY_",
233 | table));
234 | }
235 | }
236 |
237 | public static void createSignalSubscriptionTable(
238 | final String url, final String user, final String password, final String table)
239 | throws SQLException {
240 | try (final Connection conn = DriverManager.getConnection(url, user, password);
241 | final Statement stmt = conn.createStatement()) {
242 | stmt.execute(
243 | String.format(
244 | "create table if not exists %1$s (ID_ String,SIGNAL_NAME_ String,"
245 | + " TIMESTAMP_ DateTime64(3),STATE_ String,"
246 | + " CATCH_ELEMENT_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ Int64,"
247 | + " BPMN_PROCESS_ID_ String,CATCH_EVENT_ID_ String) "
248 | + " engine = ReplacingMergeTree(TIMESTAMP_) PARTITION BY toYYYYMM(TIMESTAMP_) ORDER BY ID_",
249 | table));
250 | }
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/ErrorImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.ErrorRecordValue;
12 | import java.sql.*;
13 |
14 | public class ErrorImporter {
15 | public static void batchErrorInsert(
16 | final String url,
17 | final String user,
18 | final String password,
19 | final String table,
20 | final Record> record)
21 | throws SQLException {
22 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
23 | final String sql =
24 | String.format(
25 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select POSITION_, ERROR_EVENT_POSITION_, "
26 | + " TIMESTAMP_, PROCESS_INSTANCE_KEY_, EXCEPTION_MESSAGE_,STACKTRACE_"
27 | + " from input('POSITION_ UInt64,ERROR_EVENT_POSITION_ UInt64,"
28 | + " TIMESTAMP_ DateTime64(3), "
29 | + " PROCESS_INSTANCE_KEY_ UInt64,EXCEPTION_MESSAGE_ String,"
30 | + " STACKTRACE_ String')",
31 | table);
32 |
33 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
34 | final ErrorRecordValue error = (ErrorRecordValue) record.getValue();
35 | // 记录Id
36 | ps.setLong(1, record.getPosition());
37 | // 发生位置
38 | ps.setLong(2, error.getErrorEventPosition());
39 | // 记录时间
40 | ps.setLong(3, record.getTimestamp());
41 | // 流程实例Id
42 | ps.setLong(4, error.getProcessInstanceKey());
43 | // 异常信息
44 | ps.setString(5, error.getExceptionMessage());
45 | // 堆栈
46 | ps.setString(6, error.getStacktrace());
47 | ps.addBatch();
48 | ps.executeBatch();
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/IncidentImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.intent.IncidentIntent;
12 | import io.camunda.zeebe.protocol.record.intent.Intent;
13 | import io.camunda.zeebe.protocol.record.value.IncidentRecordValue;
14 | import java.sql.*;
15 |
16 | public class IncidentImporter {
17 | public static void batchIncidentInsertOrUpdate(
18 | final String url,
19 | final String user,
20 | final String password,
21 | final String table,
22 | final Record> record)
23 | throws SQLException {
24 | final Intent intent = record.getIntent();
25 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
26 | String sql = "";
27 |
28 | if (intent == IncidentIntent.CREATED) {
29 | sql =
30 | String.format(
31 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_, BPMN_PROCESS_ID_, ERROR_MSG_, "
32 | + " ERROR_TYPE_, CREATED_, RESOLVED_, PROCESS_INSTANCE_KEY_, "
33 | + " ELEMENT_INSTANCE_KEY_, JOB_KEY_, PROCESS_DEFINITION_KEY_ "
34 | + " from input('KEY_ UInt64,BPMN_PROCESS_ID_ String, ERROR_MSG_ String,"
35 | + " ERROR_TYPE_ String,"
36 | + " CREATED_ DateTime64(3), RESOLVED_ Nullable(DateTime64(3)), PROCESS_INSTANCE_KEY_ UInt64, "
37 | + " ELEMENT_INSTANCE_KEY_ UInt64, JOB_KEY_ UInt64, PROCESS_DEFINITION_KEY_ UInt64')",
38 | table);
39 | } else if (intent == IncidentIntent.RESOLVED) {
40 | sql =
41 | String.format(
42 | "alter table %1$s update RESOLVED_ = toDateTime64(?/1000,3) where KEY_ = ?", table);
43 | }
44 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
45 | final IncidentRecordValue incident = (IncidentRecordValue) record.getValue();
46 | if (intent == IncidentIntent.CREATED) {
47 | // 记录Id
48 | ps.setLong(1, record.getKey());
49 | // 流程定义标识
50 | ps.setString(2, incident.getBpmnProcessId());
51 | // 节点定义Id
52 | ps.setString(3, incident.getErrorMessage());
53 | // 任务处理器
54 | ps.setString(4, incident.getErrorType().name());
55 | // 开始时间
56 | ps.setLong(5, record.getTimestamp());
57 | // 最后更新时间
58 | ps.setString(6, null);
59 | // 版本号
60 | ps.setLong(7, incident.getProcessInstanceKey());
61 | // 节点实例Id
62 | ps.setLong(8, incident.getElementInstanceKey());
63 | // 节点实例Id
64 | ps.setLong(9, incident.getJobKey());
65 | // 流程定义Id
66 | ps.setLong(10, incident.getProcessDefinitionKey());
67 |
68 | ps.addBatch();
69 | ps.executeBatch();
70 | } else if (intent == IncidentIntent.RESOLVED) {
71 | // 更新时间
72 | ps.setLong(1, record.getTimestamp());
73 | // 记录Id
74 | ps.setLong(2, record.getKey());
75 |
76 | System.out.println("incident----->record.getTimestamp()->" + record.getTimestamp());
77 | ps.execute();
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/JobImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.intent.Intent;
12 | import io.camunda.zeebe.protocol.record.intent.JobIntent;
13 | import io.camunda.zeebe.protocol.record.value.JobRecordValue;
14 | import java.sql.*;
15 |
16 | public class JobImporter {
17 | public static void batchJobInsertOrUpdate(
18 | final String url,
19 | final String user,
20 | final String password,
21 | final String table,
22 | final Record> record)
23 | throws SQLException {
24 | final Intent intent = record.getIntent();
25 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
26 | final String sql;
27 | if (intent == JobIntent.CREATED) {
28 | sql =
29 | String.format(
30 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_, BPMN_PROCESS_ID_, "
31 | + " ELEMENT_ID_, WORKER_, JOB_TYPE_, STATE_, RETRIES_, START_, END_, PROCESS_INSTANCE_KEY_, "
32 | + " ELEMENT_INSTANCE_KEY_, PROCESS_DEFINITION_KEY_ "
33 | + " from input('KEY_ UInt64,BPMN_PROCESS_ID_ String, ELEMENT_ID_ String,"
34 | + " WORKER_ String,JOB_TYPE_ String,STATE_ String, RETRIES_ UInt8,"
35 | + " START_ DateTime64(3), END_ Nullable(DateTime64(3)), PROCESS_INSTANCE_KEY_ UInt64, "
36 | + " ELEMENT_INSTANCE_KEY_ UInt64, PROCESS_DEFINITION_KEY_ UInt64')",
37 | table);
38 | } else {
39 | sql =
40 | String.format(
41 | "alter table %1$s update END_ = toDateTime64(?/1000,3), "
42 | + " WORKER_ =?, RETRIES_=?, STATE_=? "
43 | + " where KEY_ = ?",
44 | table);
45 | }
46 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
47 | final JobRecordValue job = (JobRecordValue) record.getValue();
48 | if (intent == JobIntent.CREATED) {
49 | // 记录Id
50 | ps.setLong(1, record.getKey());
51 | // 流程定义标识
52 | ps.setString(2, job.getBpmnProcessId());
53 | // 节点定义Id
54 | ps.setString(3, job.getElementId());
55 | // 任务处理器
56 | ps.setString(4, job.getWorker());
57 | // 任务类型
58 | ps.setString(5, job.getType());
59 | // 状态
60 | ps.setString(6, record.getIntent().name().toLowerCase());
61 | // 重试次数
62 | ps.setInt(7, job.getRetries());
63 | // 开始时间
64 | ps.setLong(8, record.getTimestamp());
65 | // 最后更新时间
66 | ps.setString(9, null);
67 | // 版本号
68 | ps.setLong(10, job.getProcessInstanceKey());
69 | // 节点实例Id
70 | ps.setLong(11, job.getElementInstanceKey());
71 | // 流程定义Id
72 | ps.setLong(12, job.getProcessDefinitionKey());
73 |
74 | ps.addBatch();
75 | ps.executeBatch();
76 | } else {
77 | // 更新时间
78 | ps.setLong(1, record.getTimestamp());
79 | // 任务处理器
80 | ps.setString(2, job.getWorker());
81 | // 重试次数
82 | ps.setInt(3, job.getRetries());
83 | // 状态
84 | ps.setString(4, record.getIntent().name().toLowerCase());
85 | // 记录Id
86 | ps.setLong(5, record.getKey());
87 |
88 | ps.execute();
89 | }
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/MessageImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.MessageRecordValue;
12 | import java.sql.*;
13 |
14 | public class MessageImporter {
15 | public static void batchMessageInsert(
16 | final String url,
17 | final String user,
18 | final String password,
19 | final String table,
20 | final Record> record)
21 | throws SQLException {
22 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
23 | final String sql =
24 | String.format(
25 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_, NAME_, "
26 | + " TIMESTAMP_, STATE_, CORRELATION_KEY_,MESSAGE_ID_,PAYLOAD_"
27 | + " from input('KEY_ UInt64,NAME_ String,"
28 | + " TIMESTAMP_ DateTime64(3), STATE_ String,"
29 | + " CORRELATION_KEY_ String,MESSAGE_ID_ String,"
30 | + " PAYLOAD_ String')",
31 | table);
32 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
33 | final MessageRecordValue msg = (MessageRecordValue) record.getValue();
34 | // 记录Id
35 | ps.setLong(1, record.getKey());
36 | // 名称
37 | ps.setString(2, msg.getName());
38 | // 记录时间
39 | ps.setLong(3, record.getTimestamp());
40 | // 状态
41 | ps.setString(4, record.getIntent().name().toLowerCase());
42 | // 关联key
43 | ps.setString(5, msg.getCorrelationKey());
44 | // 消息id
45 | ps.setString(6, msg.getMessageId());
46 | // 报文
47 | ps.setString(7, msg.getVariables().toString());
48 | ps.addBatch();
49 | ps.executeBatch();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/MessageSubscriptionImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.MessageStartEventSubscriptionRecordValue;
12 | import io.camunda.zeebe.protocol.record.value.MessageSubscriptionRecordValue;
13 | import java.sql.*;
14 | import java.util.UUID;
15 |
16 | public class MessageSubscriptionImporter {
17 | public static void batchMessageSubscriptionInsert(
18 | final String url,
19 | final String user,
20 | final String password,
21 | final String table,
22 | final Record> record)
23 | throws SQLException {
24 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
25 | final String sql =
26 | String.format(
27 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select ID_, MESSAGE_NAME_, MESSAGE_KEY_,"
28 | + " TIMESTAMP_, STATE_, PROCESS_INSTANCE_KEY_,ELEMENT_INSTANCE_KEY_,"
29 | + " PROCESS_DEFINITION_KEY_,CORRELATION_KEY_,TARGET_FLOW_NODE_ID_"
30 | + " from input('ID_ String,MESSAGE_NAME_ String,MESSAGE_KEY_ Int64,"
31 | + " TIMESTAMP_ DateTime64(3), STATE_ String,"
32 | + " PROCESS_INSTANCE_KEY_ Int64,ELEMENT_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ Int64,"
33 | + " CORRELATION_KEY_ Nullable(String),TARGET_FLOW_NODE_ID_ Nullable(String)')",
34 | table);
35 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
36 | final MessageSubscriptionRecordValue msg =
37 | (MessageSubscriptionRecordValue) record.getValue();
38 | // 记录Id
39 | ps.setString(1, generateId());
40 | // 名称
41 | ps.setString(2, msg.getMessageName());
42 | ps.setLong(3, -1L);
43 | // 记录时间
44 | ps.setLong(4, record.getTimestamp());
45 | // 状态
46 | ps.setString(5, record.getIntent().name().toLowerCase());
47 | ps.setLong(6, msg.getProcessInstanceKey());
48 | ps.setLong(7, msg.getElementInstanceKey());
49 |
50 | ps.setLong(8, -1L);
51 | // 关联key
52 | ps.setString(9, msg.getCorrelationKey());
53 |
54 | ps.setString(10, "");
55 | ps.addBatch();
56 | ps.executeBatch();
57 | }
58 | }
59 | }
60 |
61 | public static void batchMessageStartEventSubscriptionInsert(
62 | final String url,
63 | final String user,
64 | final String password,
65 | final String table,
66 | final Record> record)
67 | throws SQLException {
68 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
69 | final String sql =
70 | String.format(
71 | "insert into %1$s select ID_, MESSAGE_NAME_,MESSAGE_KEY_,"
72 | + " TIMESTAMP_, STATE_, PROCESS_INSTANCE_KEY_,ELEMENT_INSTANCE_KEY_,"
73 | + " PROCESS_DEFINITION_KEY_,CORRELATION_KEY_,TARGET_FLOW_NODE_ID_"
74 | + " from input('ID_ String,MESSAGE_NAME_ String,MESSAGE_KEY_ Int64,"
75 | + " TIMESTAMP_ DateTime64(3), STATE_ String,"
76 | + " PROCESS_INSTANCE_KEY_ Int64,ELEMENT_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ Int64,"
77 | + " CORRELATION_KEY_ Nullable(String),TARGET_FLOW_NODE_ID_ Nullable(String)')",
78 | table);
79 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
80 | final MessageStartEventSubscriptionRecordValue msg =
81 | (MessageStartEventSubscriptionRecordValue) record.getValue();
82 | // 记录Id
83 | ps.setString(1, generateId());
84 | // 消息名称
85 | ps.setString(2, msg.getMessageName());
86 | // 消息实例Key
87 | ps.setLong(3, msg.getMessageKey());
88 | // 记录时间
89 | ps.setLong(4, record.getTimestamp());
90 | // 状态
91 | ps.setString(5, record.getIntent().name().toLowerCase());
92 | ps.setLong(6, msg.getProcessInstanceKey());
93 | ps.setLong(7, -1);
94 |
95 | ps.setLong(8, msg.getProcessDefinitionKey());
96 | // 关联key
97 | ps.setString(9, msg.getCorrelationKey());
98 |
99 | ps.setString(10, msg.getStartEventId());
100 | ps.addBatch();
101 | ps.executeBatch();
102 | }
103 | }
104 | }
105 |
106 | private static String generateId() {
107 | return UUID.randomUUID().toString();
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/ProcessImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.deployment.Process;
12 | import java.nio.charset.StandardCharsets;
13 | import java.sql.*;
14 |
15 | public class ProcessImporter {
16 | public static void batchProcessInsert(
17 | final String url,
18 | final String user,
19 | final String password,
20 | final String table,
21 | final Record> record)
22 | throws SQLException {
23 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
24 | final String sql =
25 | String.format(
26 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_,"
27 | + " BPMN_PROCESS_ID_, RESOURCE_NAME_, "
28 | + " TIMESTAMP_, PARTITION_ID_, POSITION_, VERSION_, RESOURCE_"
29 | + " from input('KEY_ UInt64, BPMN_PROCESS_ID_ String, RESOURCE_NAME_ String,"
30 | + " TIMESTAMP_ DateTime64(3), PARTITION_ID_ UInt16, POSITION_ UInt64,VERSION_ UInt16,RESOURCE_ String')",
31 | table);
32 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
33 | final Process process = (Process) record.getValue();
34 | // 流程定义Id
35 | ps.setLong(1, record.getKey());
36 | // 流程定义键值
37 | ps.setString(2, process.getBpmnProcessId());
38 | // 流程定义文件名
39 | ps.setString(3, process.getResourceName());
40 | // 部署时间
41 | ps.setLong(4, record.getTimestamp());
42 | // 所属分区
43 | ps.setInt(5, record.getPartitionId());
44 | // 位置
45 | ps.setLong(6, record.getPosition());
46 | // 版本号
47 | ps.setInt(7, process.getVersion());
48 | // 模型定义信息
49 | final String resource = new String(process.getResource(), StandardCharsets.UTF_8);
50 | ps.setString(8, resource);
51 |
52 | ps.addBatch();
53 | ps.executeBatch();
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/ProcessInstanceImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.intent.Intent;
12 | import io.camunda.zeebe.protocol.record.intent.ProcessInstanceIntent;
13 | import io.camunda.zeebe.protocol.record.value.BpmnElementType;
14 | import io.camunda.zeebe.protocol.record.value.ProcessInstanceRecordValue;
15 | import java.sql.*;
16 |
17 | public class ProcessInstanceImporter {
18 |
19 | public static void batchProcessInstanceInsertOrUpdate(
20 | final String url,
21 | final String user,
22 | final String password,
23 | final String table,
24 | final Record> record)
25 | throws SQLException {
26 | final Intent intent = record.getIntent();
27 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
28 | final String sql;
29 | if (intent == ProcessInstanceIntent.ELEMENT_ACTIVATED) {
30 | sql =
31 | String.format(
32 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_, BPMN_PROCESS_ID_, "
33 | + " PROCESS_DEFINITION_KEY_, START_,END_, PARTITION_ID_, VERSION_, STATE_,"
34 | + " PARENT_PROCESS_INSTANCE_KEY_, PARENT_ELEMENT_INSTANCE_KEY_"
35 | + " from input('KEY_ UInt64,BPMN_PROCESS_ID_ String,"
36 | + " PROCESS_DEFINITION_KEY_ UInt64, START_ DateTime64(3), END_ Nullable(DateTime64(3)),"
37 | + " PARTITION_ID_ UInt16, VERSION_ UInt16,STATE_ String, "
38 | + " PARENT_PROCESS_INSTANCE_KEY_ Int64, PARENT_ELEMENT_INSTANCE_KEY_ Int64')",
39 | table);
40 | } else {
41 | sql =
42 | String.format(
43 | "alter table %1$s update END_ = toDateTime64(?/1000,3),STATE_ =? where KEY_ = ?",
44 | table);
45 | }
46 |
47 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
48 | final ProcessInstanceRecordValue processInstance =
49 | (ProcessInstanceRecordValue) record.getValue();
50 | if (BpmnElementType.PROCESS.name().equals(processInstance.getBpmnElementType().name())) {
51 | if (intent == ProcessInstanceIntent.ELEMENT_ACTIVATED) {
52 | // 流程实例Id
53 | ps.setLong(1, record.getKey());
54 | // 流程定义键值
55 | ps.setString(2, processInstance.getBpmnProcessId());
56 | // 流程定义Id
57 | ps.setLong(3, processInstance.getProcessDefinitionKey());
58 | // 创建时间
59 | ps.setLong(4, record.getTimestamp());
60 | ps.setString(5, null);
61 | // 所属分区
62 | ps.setInt(6, record.getPartitionId());
63 | // 版本号
64 | ps.setInt(7, processInstance.getVersion());
65 | // 状态
66 | ps.setString(8, "Active");
67 | // 父流程实例Id
68 | ps.setLong(9, processInstance.getParentProcessInstanceKey());
69 | // 父节点实例Id
70 | ps.setLong(10, processInstance.getParentElementInstanceKey());
71 | ps.addBatch();
72 | ps.executeBatch();
73 | } else if (intent == ProcessInstanceIntent.ELEMENT_COMPLETED) {
74 | // 结束时间
75 | ps.setLong(1, record.getTimestamp());
76 | // 状态
77 | ps.setString(2, "Completed");
78 | // 流程实例Id
79 | ps.setLong(3, record.getKey());
80 | // System.out.println("record.getTimestamp()->"+record.getTimestamp());
81 | ps.execute();
82 | } else if (intent == ProcessInstanceIntent.ELEMENT_TERMINATED) {
83 | // 结束时间
84 | ps.setLong(1, record.getTimestamp());
85 | // 状态
86 | ps.setString(2, "Terminated");
87 | // 流程实例Id
88 | ps.setLong(3, record.getKey());
89 |
90 | ps.execute();
91 | }
92 | }
93 | }
94 | }
95 | }
96 |
97 | public static void batchElementInstanceInsert(
98 | final String url,
99 | final String user,
100 | final String password,
101 | final String table,
102 | final Record> record)
103 | throws SQLException {
104 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
105 | final String sql =
106 | String.format(
107 | "insert into %1$s select ID,KEY_, BPMN_PROCESS_ID_, PROCESS_DEFINITION_KEY_, "
108 | + " TIMESTAMP_,INTENT_ ,PARTITION_ID_,"
109 | + " POSITION_, PROCESS_INSTANCE_KEY_,"
110 | + " FLOW_SCOPE_KEY_,ELEMENT_ID_,BPMN_ELEMENT_TYPE_"
111 | + " from input('ID String,KEY_ UInt64,BPMN_PROCESS_ID_ String,"
112 | + " PROCESS_DEFINITION_KEY_ UInt64, TIMESTAMP_ DateTime64(3), "
113 | + " INTENT_ String,PARTITION_ID_ UInt16,"
114 | + " POSITION_ UInt64, PROCESS_INSTANCE_KEY_ UInt64,"
115 | + " FLOW_SCOPE_KEY_ Int64,ELEMENT_ID_ String,BPMN_ELEMENT_TYPE_ String')",
116 | table);
117 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
118 |
119 | final ProcessInstanceRecordValue processInstance =
120 | (ProcessInstanceRecordValue) record.getValue();
121 | // 记录Id
122 | ps.setString(1, record.getPartitionId() + "-" + record.getPosition());
123 | // 元素记录Id
124 | ps.setLong(2, record.getKey());
125 | // 流程定义键值
126 | ps.setString(3, processInstance.getBpmnProcessId());
127 | // 流程定义Id
128 | ps.setLong(4, processInstance.getProcessDefinitionKey());
129 | // 创建时间
130 | ps.setLong(5, record.getTimestamp());
131 | // 活动状态
132 | ps.setString(6, record.getIntent().name());
133 | // 所属分区
134 | ps.setInt(7, record.getPartitionId());
135 | // 版本号
136 | ps.setLong(8, record.getPosition());
137 | // 流程实例Id
138 | ps.setLong(9, processInstance.getProcessInstanceKey());
139 | // 范围Id
140 | ps.setLong(10, processInstance.getFlowScopeKey());
141 | // 元素定义Id
142 | ps.setString(11, processInstance.getElementId());
143 | // 元素定义类型
144 | ps.setString(12, processInstance.getBpmnElementType().name());
145 | ps.addBatch();
146 | ps.executeBatch();
147 | } catch (final SQLException e) {
148 | e.printStackTrace();
149 | }
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/SignalSubscriptionImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.SignalSubscriptionRecordValue;
12 | import java.sql.*;
13 | import java.util.UUID;
14 |
15 | public class SignalSubscriptionImporter {
16 |
17 | public static void batchSignalSubscriptionInsert(
18 | final String url,
19 | final String user,
20 | final String password,
21 | final String table,
22 | final Record> record)
23 | throws SQLException {
24 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
25 | final String sql =
26 | String.format(
27 | "insert into %1$s select ID_, SIGNAL_NAME_,"
28 | + " TIMESTAMP_, STATE_, CATCH_ELEMENT_INSTANCE_KEY_,"
29 | + " PROCESS_DEFINITION_KEY_,BPMN_PROCESS_ID_,CATCH_EVENT_ID_"
30 | + " from input('ID_ String,SIGNAL_NAME_ String,"
31 | + " TIMESTAMP_ DateTime64(3), STATE_ String,"
32 | + " CATCH_ELEMENT_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ Int64,"
33 | + " BPMN_PROCESS_ID_ String,CATCH_EVENT_ID_ String')",
34 | table);
35 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
36 | final SignalSubscriptionRecordValue signal =
37 | (SignalSubscriptionRecordValue) record.getValue();
38 | // 记录Id
39 | ps.setString(1, generateId());
40 | // 信号名称
41 | ps.setString(2, signal.getSignalName());
42 | // 记录时间
43 | ps.setLong(3, record.getTimestamp());
44 | // 状态
45 | ps.setString(4, record.getIntent().name().toLowerCase());
46 | ps.setLong(5, signal.getCatchEventInstanceKey());
47 |
48 | ps.setLong(6, signal.getProcessDefinitionKey());
49 | // 关联key
50 | ps.setString(7, signal.getBpmnProcessId());
51 |
52 | ps.setString(8, signal.getCatchEventId());
53 | ps.addBatch();
54 | ps.executeBatch();
55 | }
56 | }
57 | }
58 |
59 | private static String generateId() {
60 | return UUID.randomUUID().toString();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/TimerImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.TimerRecordValue;
12 | import java.sql.*;
13 |
14 | public class TimerImporter {
15 | public static void batchTimerInsert(
16 | final String url,
17 | final String user,
18 | final String password,
19 | final String table,
20 | final Record> record)
21 | throws SQLException {
22 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
23 | final String sql =
24 | String.format(
25 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select KEY_, STATE_, REPETITIONS, "
26 | + " TIMESTAMP_, DUE_DATE_, PROCESS_INSTANCE_KEY_, PROCESS_DEFINITION_KEY_,ELEMENT_INSTANCE_KEY_, TARGET_ELEMENT_ID_"
27 | + " from input('KEY_ UInt64,STATE_ String, REPETITIONS Int16,"
28 | + " TIMESTAMP_ DateTime64(3), DUE_DATE_ DateTime64(3), "
29 | + " PROCESS_INSTANCE_KEY_ Int64,PROCESS_DEFINITION_KEY_ UInt64,"
30 | + " ELEMENT_INSTANCE_KEY_ Int64, TARGET_ELEMENT_ID_ String')",
31 | table);
32 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
33 | final TimerRecordValue timer = (TimerRecordValue) record.getValue();
34 | // 记录Id
35 | ps.setLong(1, record.getKey());
36 | // 状态
37 | ps.setString(2, record.getIntent().name().toLowerCase());
38 | // 重复次数
39 | ps.setInt(3, timer.getRepetitions());
40 | // 记录时间
41 | ps.setLong(4, record.getTimestamp());
42 | // 截止时间
43 | ps.setLong(5, timer.getDueDate());
44 | // 流程实例Id
45 | ps.setLong(6, timer.getProcessInstanceKey());
46 | // 流程定义id
47 | ps.setLong(7, timer.getProcessDefinitionKey());
48 | // 节点实例Id
49 | ps.setLong(8, timer.getElementInstanceKey());
50 | // 节点Id
51 | ps.setString(9, timer.getTargetElementId());
52 |
53 | ps.addBatch();
54 | ps.executeBatch();
55 |
56 | } catch (final Exception e) {
57 | e.printStackTrace();
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/io/zeebe/clickhouse/exporter/importer/VariableImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter.importer;
9 |
10 | import io.camunda.zeebe.protocol.record.Record;
11 | import io.camunda.zeebe.protocol.record.value.VariableRecordValue;
12 | import java.sql.*;
13 |
14 | public class VariableImporter {
15 |
16 | public static void batchVariableInsert(
17 | final String url,
18 | final String user,
19 | final String password,
20 | final String table,
21 | final Record> record)
22 | throws SQLException {
23 | try (final Connection conn = DriverManager.getConnection(url, user, password)) {
24 |
25 | final String sql =
26 | String.format(
27 | "insert into %1$s SETTINGS async_insert=1, wait_for_async_insert=0 select ID, NAME_, VALUE_, "
28 | + " TIMESTAMP_, PARTITION_ID_, POSITION_, "
29 | + " PROCESS_INSTANCE_KEY_, PROCESS_DEFINITION_KEY_,SCOPE_KEY_, STATE_"
30 | + " from input('ID String,NAME_ String, VALUE_ String,"
31 | + " TIMESTAMP_ DateTime64(3), PARTITION_ID_ UInt16, POSITION_ UInt64,"
32 | + " PROCESS_INSTANCE_KEY_ UInt64,PROCESS_DEFINITION_KEY_ UInt64,"
33 | + " SCOPE_KEY_ Int64, STATE_ String')",
34 | table);
35 | try (final PreparedStatement ps = conn.prepareStatement(sql)) {
36 | final VariableRecordValue variable = (VariableRecordValue) record.getValue();
37 | // 记录Id
38 | ps.setString(1, String.format("%s-%s", record.getPartitionId(), record.getPosition()));
39 | // ps.setString(1,generateId());
40 | // 变量名
41 | ps.setString(2, variable.getName());
42 | // 变量值
43 | ps.setString(3, variable.getValue());
44 | // 记录时间
45 | ps.setLong(4, record.getTimestamp());
46 | // 所属分区
47 | ps.setInt(5, record.getPartitionId());
48 | // 位置
49 | ps.setLong(6, record.getPosition());
50 | // 流程实例Id
51 | ps.setLong(7, variable.getProcessInstanceKey());
52 | // 流程定义id
53 | ps.setLong(8, variable.getProcessDefinitionKey());
54 | // 所属范围
55 | ps.setLong(9, variable.getScopeKey());
56 | // 状态
57 | ps.setString(10, record.getIntent().name().toLowerCase());
58 |
59 | ps.addBatch();
60 | ps.executeBatch();
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/test/java/io/zeebe/clickhouse/exporter/ClickHouseExporterIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
3 | * one or more contributor license agreements. See the NOTICE file distributed
4 | * with this work for additional information regarding copyright ownership.
5 | * Licensed under the Zeebe Community License 1.1. You may not use this file
6 | * except in compliance with the Zeebe Community License 1.1.
7 | */
8 | package io.zeebe.clickhouse.exporter;
9 |
10 | import static org.assertj.core.api.Assertions.assertThat;
11 |
12 | import com.clickhouse.data.ClickHouseDataType;
13 | import io.camunda.zeebe.client.ZeebeClient;
14 | import io.camunda.zeebe.client.api.response.DeploymentEvent;
15 | import io.camunda.zeebe.model.bpmn.Bpmn;
16 | import io.camunda.zeebe.model.bpmn.BpmnModelInstance;
17 | import io.zeebe.containers.ZeebeContainer;
18 | import java.sql.*;
19 | import java.util.concurrent.TimeUnit;
20 | import org.agrona.CloseHelper;
21 | import org.junit.Test;
22 | import org.junit.jupiter.api.AfterEach;
23 | import org.junit.jupiter.api.Timeout;
24 | import org.junit.jupiter.api.parallel.Execution;
25 | import org.junit.jupiter.api.parallel.ExecutionMode;
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 | import org.testcontainers.clickhouse.ClickHouseContainer;
29 | import org.testcontainers.containers.Network;
30 | import org.testcontainers.containers.output.Slf4jLogConsumer;
31 | import org.testcontainers.junit.jupiter.Container;
32 | import org.testcontainers.junit.jupiter.Testcontainers;
33 | import org.testcontainers.utility.DockerImageName;
34 | import org.testcontainers.utility.MountableFile;
35 |
36 | @Testcontainers
37 | @Timeout(value = 2, unit = TimeUnit.MINUTES)
38 | @Execution(ExecutionMode.CONCURRENT)
39 | public class ClickHouseExporterIT {
40 |
41 | private static final String JOB_TYPE = "work";
42 | private static final String MESSAGE_NAME = "catch";
43 | private static final String PROCESS_NAME = "testProcess";
44 | private static final String PROCESS_FILE_NAME = "sample_workflow.bpmn";
45 | private static final String TASK_NAME = "task";
46 | private static final BpmnModelInstance SAMPLE_PROCESS =
47 | Bpmn.createExecutableProcess(PROCESS_NAME)
48 | .startEvent()
49 | .intermediateCatchEvent(
50 | "message",
51 | e -> e.message(m -> m.name(MESSAGE_NAME).zeebeCorrelationKeyExpression("orderId")))
52 | .serviceTask(TASK_NAME, t -> t.zeebeJobType(JOB_TYPE).zeebeTaskHeader("foo", "bar"))
53 | .endEvent()
54 | .done();
55 | private final MountableFile exporterJar =
56 | MountableFile.forClasspathResource("zeebe-clickhouse-exporter.jar", 775);
57 | private final MountableFile exporterConfig =
58 | MountableFile.forClasspathResource("application.yaml", 775);
59 | private final MountableFile loggingConfig =
60 | MountableFile.forClasspathResource("logback-test.xml", 775);
61 | private final Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(newContainerLogger(), true);
62 | private final Network network = Network.newNetwork();
63 |
64 | @Container
65 | public ClickHouseContainer clickHouse =
66 | new ClickHouseContainer(
67 | DockerImageName.parse("clickhouse/clickhouse-server:22.8.15.23-alpine"))
68 | .withNetwork(network)
69 | .withNetworkAliases("clickhouse")
70 | .withExposedPorts(8123);
71 |
72 | @Container
73 | public ZeebeContainer zeebeContainer =
74 | new ZeebeContainer(DockerImageName.parse("camunda/zeebe:8.2.0"))
75 | .withNetwork(network)
76 | .withNetworkAliases("zeebe")
77 | .withEnv("ZEEBE_BROKER_NETWORK_ADVERTISEDHOST", "zeebe")
78 | .withEnv("ZEEBE_CLICKHOUSE_URL", "jdbc:ch://clickhouse/default")
79 | .withEnv("ZEEBE_CLICKHOUSE_USER", "default")
80 | .withEnv("ZEEBE_CLICKHOUSE_PASSWORD", "")
81 | .withEnv("ZEEBE_LOG_LEVEL", "debug")
82 | .withCopyFileToContainer(
83 | exporterJar, "/usr/local/zeebe/exporters/zeebe-clickhouse-exporter.jar")
84 | .withCopyFileToContainer(exporterConfig, "/usr/local/zeebe/config/application.yaml")
85 | .withCopyFileToContainer(loggingConfig, "/usr/local/zeebe/config/logback-test.xml")
86 | .withEnv(
87 | "SPRING_CONFIG_ADDITIONAL_LOCATION", "file:/usr/local/zeebe/config/application.yaml")
88 | .withLogConsumer(logConsumer);
89 |
90 | private ZeebeClient zeebeClient;
91 |
92 | private static Logger newContainerLogger() {
93 | return LoggerFactory.getLogger(ClickHouseExporterIT.class.getName() + "." + "zeebeContainer");
94 | }
95 |
96 | @AfterEach
97 | void tearDown() {
98 | CloseHelper.quietCloseAll(zeebeClient, zeebeContainer, clickHouse, network);
99 | }
100 |
101 | @Test
102 | public void testClickHouseContainer() throws SQLException {
103 | clickHouse.start();
104 |
105 | final String sql = "select cast(1 as UInt64) a, cast([1, 2] as Array(Int8)) b";
106 | try (final Connection conn =
107 | DriverManager.getConnection(
108 | clickHouse.getJdbcUrl(), clickHouse.getUsername(), clickHouse.getPassword());
109 | final Statement stmt = conn.createStatement();
110 | final ResultSet rs = stmt.executeQuery(sql)) {
111 |
112 | assertThat(rs.next()).isTrue();
113 | assertThat(rs.getMetaData().getColumnTypeName(1)).isEqualTo(ClickHouseDataType.UInt64.name());
114 | assertThat(rs.getMetaData().getColumnTypeName(2)).isEqualTo("Array(Int8)");
115 | assertThat(rs.next()).isFalse();
116 | }
117 | }
118 |
119 | @Test
120 | public void shouldExportProcessToClickHouse() throws SQLException, InterruptedException {
121 | // given
122 | clickHouse.start();
123 | zeebeContainer.start();
124 | zeebeClient = getLazyZeebeClient();
125 |
126 | // when
127 | final DeploymentEvent deploymentEvent =
128 | zeebeClient
129 | .newDeployResourceCommand()
130 | .addProcessModel(SAMPLE_PROCESS, PROCESS_FILE_NAME)
131 | .send()
132 | .join();
133 |
134 | Thread.sleep(1000);
135 | // then
136 | final String sql =
137 | "select KEY_,BPMN_PROCESS_ID_,RESOURCE_NAME_,TIMESTAMP_,PARTITION_ID_,POSITION_,VERSION_,RESOURCE_ from PROCESS";
138 |
139 | try (final Connection conn =
140 | DriverManager.getConnection(
141 | clickHouse.getJdbcUrl(), clickHouse.getUsername(), clickHouse.getPassword());
142 | final Statement stmt = conn.createStatement();
143 | final ResultSet rs = stmt.executeQuery(sql)) {
144 |
145 | assertThat(rs.next()).isTrue();
146 | assertThat(rs.getMetaData().getColumnTypeName(1)).isEqualTo(ClickHouseDataType.UInt64.name());
147 | assertThat(rs.getMetaData().getColumnTypeName(2)).isEqualTo(ClickHouseDataType.String.name());
148 | assertThat(rs.getMetaData().getColumnTypeName(3)).isEqualTo(ClickHouseDataType.String.name());
149 | assertThat(rs.getMetaData().getColumnTypeName(4)).isEqualTo("DateTime64(3)");
150 | assertThat(rs.getMetaData().getColumnTypeName(5)).isEqualTo(ClickHouseDataType.UInt16.name());
151 | assertThat(rs.getMetaData().getColumnTypeName(6)).isEqualTo(ClickHouseDataType.UInt64.name());
152 | assertThat(rs.getMetaData().getColumnTypeName(7)).isEqualTo(ClickHouseDataType.UInt16.name());
153 | assertThat(rs.getMetaData().getColumnTypeName(8)).isEqualTo(ClickHouseDataType.String.name());
154 |
155 | assertThat(rs.getLong(1))
156 | .isEqualTo(deploymentEvent.getProcesses().get(0).getProcessDefinitionKey());
157 | assertThat(rs.getString(2)).isEqualTo(PROCESS_NAME);
158 | assertThat(rs.getString(3)).isEqualTo(PROCESS_FILE_NAME);
159 | assertThat(rs.getInt(7)).isEqualTo(deploymentEvent.getProcesses().get(0).getVersion());
160 | assertThat(rs.getString(8)).isEqualTo(Bpmn.convertToString(SAMPLE_PROCESS));
161 |
162 | assertThat(rs.next()).isFalse();
163 | }
164 | }
165 |
166 | private ZeebeClient getLazyZeebeClient() {
167 | if (zeebeClient == null) {
168 | zeebeClient =
169 | ZeebeClient.newClientBuilder()
170 | .gatewayAddress(zeebeContainer.getExternalGatewayAddress())
171 | .usePlaintext()
172 | .build();
173 | }
174 | return zeebeClient;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/test/resources/application.yaml:
--------------------------------------------------------------------------------
1 | zeebe:
2 | broker:
3 | exporters:
4 | clickhouse:
5 | className: io.zeebe.clickhouse.exporter.ClickHouseExporter
6 | jarPath: exporters/zeebe-clickhouse-exporter.jar
7 |
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------