├── .github
├── .editorconfig
├── dependabot.yaml
├── event.json
└── workflows
│ ├── ci.yaml
│ └── release.yaml
├── .gitignore
├── .go-version
├── .idea
├── log-generator.iml
├── misc.xml
├── modules.xml
├── vcs.xml
└── watcherTasks.xml
├── .licensei.toml
├── Dockerfile
├── LICENSE
├── Log-Generator.postman_collection.json
├── Makefile
├── README.md
├── charts-docs
├── README.md
└── templates
│ ├── README.md.gotmpl
│ └── overrides.gotmpl
├── charts
└── log-generator
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── README.md.gotmpl
│ ├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── configmap.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── servicemonitor.yaml
│ └── values.yaml
├── conf
├── config.ini.sample
└── configuration.go
├── formats
├── custom
│ ├── go.mod
│ ├── go.sum
│ └── stub.go
├── golang
│ └── golang.go
├── logfactory.go
├── logfactory_test.go
└── web
│ ├── apache.tmpl
│ ├── nginx.tmpl
│ └── web.go
├── go.mod
├── go.sum
├── log
├── Makefile
├── go.mod
├── go.sum
├── log.go
└── template.go
├── loggen
├── loggen.go
└── writers.go
├── main.go
├── metrics
└── metrics.go
└── stress
├── cpu.go
└── memory.go
/.github/.editorconfig:
--------------------------------------------------------------------------------
1 | [{*.yaml,*.yml}]
2 | indent_size = 2
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | updates:
4 | - package-ecosystem: gomod
5 | directory: /
6 | schedule:
7 | interval: daily
8 | groups:
9 | gomod:
10 | patterns:
11 | - "*"
12 |
13 | - package-ecosystem: docker
14 | directory: /
15 | schedule:
16 | interval: daily
17 | groups:
18 | docker:
19 | patterns:
20 | - "*"
21 |
22 | - package-ecosystem: github-actions
23 | directory: /
24 | schedule:
25 | interval: daily
26 | groups:
27 | github-actions:
28 | patterns:
29 | - "*"
30 |
--------------------------------------------------------------------------------
/.github/event.json:
--------------------------------------------------------------------------------
1 | {
2 | "repository": {
3 | "name": "log-generator"
4 | },
5 | "inputs": {
6 | "release": false,
7 | "publish": false
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 |
9 | jobs:
10 | build-and-test:
11 | name: Build and test
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: Checkout code
16 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
17 |
18 | - name: Set up Go
19 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
20 | with:
21 | go-version-file: '.go-version'
22 |
23 | - name: Build
24 | run: make GOFLAGS="-v" build
25 |
26 | - name: Test
27 | run: make GOFLAGS="-v" test
28 |
29 | - name: Check diff
30 | run: make check-diff
31 |
32 | license-check:
33 | name: License check
34 | runs-on: ubuntu-latest
35 |
36 | steps:
37 | - name: Checkout code
38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
39 |
40 | - name: Set up Go
41 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
42 | with:
43 | go-version-file: '.go-version'
44 |
45 | - name: Cache licenses
46 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
47 | with:
48 | key: licensei-v2-${{ hashFiles('go.sum') }}
49 | path: |
50 | .licensei.cache
51 | restore-keys: |
52 | licensei-v2
53 |
54 | - name: Download license information for dependencies
55 | env:
56 | GITHUB_TOKEN: ${{ github.token }}
57 | run: make license-cache
58 |
59 | - name: Check licenses
60 | env:
61 | GITHUB_TOKEN: ${{ github.token }}
62 | run: make license-check
63 |
64 | artifacts:
65 | name: Artifacts
66 | uses: kube-logging/logging-operator/.github/workflows/artifacts.yaml@5.4.0
67 | with:
68 | version: "latest"
69 | publish: ${{ github.event_name == 'push' }}
70 | permissions:
71 | contents: read
72 | packages: write
73 | id-token: write
74 | security-events: write
75 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags: ["v[0-9]+.[0-9]+.[0-9]+*"]
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | artifacts:
12 | name: Artifacts
13 | uses: kube-logging/logging-operator/.github/workflows/artifacts.yaml@5.4.0
14 | with:
15 | version: ${{ github.ref_name }}
16 | publish: true
17 | release: true
18 | permissions:
19 | contents: read
20 | packages: write
21 | id-token: write
22 | security-events: write
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Temporary Build Files
2 | build/_output
3 | build/_test
4 | # Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
5 | ### Emacs ###
6 | # -*- mode: gitignore; -*-
7 | *~
8 | \#*\#
9 | /.emacs.desktop
10 | /.emacs.desktop.lock
11 | *.elc
12 | auto-save-list
13 | tramp
14 | .\#*
15 | # Org-mode
16 | .org-id-locations
17 | *_archive
18 | # flymake-mode
19 | *_flymake.*
20 | # eshell files
21 | /eshell/history
22 | /eshell/lastdir
23 | # elpa packages
24 | /elpa/
25 | # reftex files
26 | *.rel
27 | # AUCTeX auto folder
28 | /auto/
29 | # cask packages
30 | .cask/
31 | dist/
32 | # Flycheck
33 | flycheck_*.el
34 | # server auth directory
35 | /server/
36 | # projectiles files
37 | .projectile
38 | projectile-bookmarks.eld
39 | # directory configuration
40 | .dir-locals.el
41 | # saveplace
42 | places
43 | # url cache
44 | url/cache/
45 | # cedet
46 | ede-projects.el
47 | # smex
48 | smex-items
49 | # company-statistics
50 | company-statistics-cache.el
51 | # anaconda-mode
52 | anaconda-mode/
53 | ### Go ###
54 | # Binaries for programs and plugins
55 | *.exe
56 | *.exe~
57 | *.dll
58 | *.so
59 | *.dylib
60 | # Test binary, build with 'go test -c'
61 | *.test
62 | # Output of the go coverage tool, specifically when used with LiteIDE
63 | *.out
64 | ### Vim ###
65 | # swap
66 | .sw[a-p]
67 | .*.sw[a-p]
68 | # session
69 | Session.vim
70 | # temporary
71 | .netrwhist
72 | # auto-generated tag files
73 | tags
74 | ### VisualStudioCode ###
75 | .vscode/*
76 | .history
77 | # End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
78 |
79 | ### Idea ###
80 | .idea/*
81 | !/.idea/copyright/
82 | !/.idea/runConfigurations/
83 | !/.idea/modules.xml
84 | !/.idea/*.iml
85 |
86 | bin
87 | vendor
88 | testbin
89 |
90 |
91 | #Config
92 | conf/config.toml
93 | conf/config.ini
94 |
95 | .licensei.cache
96 |
97 | .DS_Store
98 |
99 | formats/custom-impl
100 | go.work*
101 |
--------------------------------------------------------------------------------
/.go-version:
--------------------------------------------------------------------------------
1 | 1.23.6
2 |
--------------------------------------------------------------------------------
/.idea/log-generator.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/watcherTasks.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.licensei.toml:
--------------------------------------------------------------------------------
1 | approved = [
2 | "mit",
3 | "apache-2.0",
4 | "bsd-3-clause",
5 | "bsd-2-clause",
6 | "mpl-2.0",
7 | ]
8 |
9 | ignored = [
10 | # Unsupported VCS
11 | "cloud.google.com/go",
12 | "cloud.google.com/go/storage",
13 | "google.golang.org/api",
14 | "google.golang.org/protobuf",
15 | ]
16 |
17 | [header]
18 | ignorePaths = ["vendor", ".gen", "plz-out", "formats/custom-impl"]
19 | ignoreFiles = ["mock_*.go", "*_gen.go", "zz_generated.*.go", "generated.go"]
20 | authors = ["Banzai Cloud", "Cisco Systems, Inc. and/or its affiliates", "Kube logging authors"]
21 | template = """// Copyright © :YEAR: :AUTHOR:
22 | //
23 | // Licensed under the Apache License, Version 2.0 (the "License");
24 | // you may not use this file except in compliance with the License.
25 | // You may obtain a copy of the License at
26 | //
27 | // http://www.apache.org/licenses/LICENSE-2.0
28 | //
29 | // Unless required by applicable law or agreed to in writing, software
30 | // distributed under the License is distributed on an "AS IS" BASIS,
31 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32 | // See the License for the specific language governing permissions and
33 | // limitations under the License."""
34 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM --platform=$BUILDPLATFORM golang:1.24.3-alpine3.20@sha256:9f98e9893fbc798c710f3432baa1e0ac6127799127c3101d2c263c3a954f0abe AS builder
2 |
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 | ARG TARGETPLATFORM
6 | ARG BUILDFLAGS
7 |
8 | RUN apk -U add make
9 |
10 | WORKDIR /workspace
11 |
12 | # Copy the Go Modules manifests
13 | COPY go.mod go.mod
14 | COPY go.sum go.sum
15 |
16 | # cache deps before building and copying source so that we don't need to re-download as much
17 | # and so that source changes don't invalidate our downloaded layer
18 | RUN go mod download
19 |
20 | # Copy the go source
21 | ADD . .
22 |
23 | # Build
24 | RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH make $BUILDFLAGS build
25 |
26 | # Use distroless as minimal base image to package the manager binary
27 | # Refer to https://github.com/GoogleContainerTools/distroless for more details
28 | FROM gcr.io/distroless/static:latest
29 |
30 | WORKDIR /
31 |
32 | COPY --from=builder /workspace/bin/loggen .
33 |
34 | ENTRYPOINT ["/loggen"]
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/Log-Generator.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "e40de9ff-249e-433b-91c8-be0cded72340",
4 | "name": "Log-Generator",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Test",
10 | "item": [
11 | {
12 | "name": "Loggen",
13 | "item": [
14 | {
15 | "name": "loggen",
16 | "event": [
17 | {
18 | "listen": "test",
19 | "script": {
20 | "exec": [
21 | "pm.test(\"Status test\", function () {",
22 | " pm.response.to.have.status(200);",
23 | "});",
24 | ""
25 | ],
26 | "type": "text/javascript"
27 | }
28 | }
29 | ],
30 | "protocolProfileBehavior": {
31 | "disableBodyPruning": true
32 | },
33 | "request": {
34 | "method": "GET",
35 | "header": [],
36 | "body": {
37 | "mode": "raw",
38 | "raw": ""
39 | },
40 | "url": {
41 | "raw": "{{baseUrl}}/loggen",
42 | "host": [
43 | "{{baseUrl}}"
44 | ],
45 | "path": [
46 | "loggen"
47 | ]
48 | }
49 | },
50 | "response": []
51 | },
52 | {
53 | "name": "loggen",
54 | "event": [
55 | {
56 | "listen": "test",
57 | "script": {
58 | "exec": [
59 | "pm.test(\"Status test\", function () {",
60 | " pm.response.to.have.status(200);",
61 | "});",
62 | "",
63 | "pm.test(\"Content test\", () => {",
64 | " const responseJson = pm.response.json();",
65 | " pm.expect(responseJson.type).to.eql(\"web\");",
66 | " pm.expect(responseJson.format).to.eql(\"nginx\");",
67 | " pm.expect(responseJson.count).to.eql(5);",
68 | "});"
69 | ],
70 | "type": "text/javascript"
71 | }
72 | }
73 | ],
74 | "request": {
75 | "method": "POST",
76 | "header": [],
77 | "body": {
78 | "mode": "raw",
79 | "raw": "{ \"type\": \"web\", \"format\": \"nginx\", \"count\": 5 }",
80 | "options": {
81 | "raw": {
82 | "language": "json"
83 | }
84 | }
85 | },
86 | "url": {
87 | "raw": "{{baseUrl}}/loggen",
88 | "host": [
89 | "{{baseUrl}}"
90 | ],
91 | "path": [
92 | "loggen"
93 | ]
94 | }
95 | },
96 | "response": []
97 | }
98 | ]
99 | },
100 | {
101 | "name": "Memory",
102 | "item": [
103 | {
104 | "name": "memory",
105 | "event": [
106 | {
107 | "listen": "test",
108 | "script": {
109 | "exec": [
110 | "pm.test(\"Status test\", function () {",
111 | " pm.response.to.have.status(200);",
112 | "});",
113 | ""
114 | ],
115 | "type": "text/javascript"
116 | }
117 | }
118 | ],
119 | "protocolProfileBehavior": {
120 | "disableBodyPruning": true
121 | },
122 | "request": {
123 | "method": "GET",
124 | "header": [],
125 | "body": {
126 | "mode": "raw",
127 | "raw": ""
128 | },
129 | "url": {
130 | "raw": "{{baseUrl}}/memory",
131 | "host": [
132 | "{{baseUrl}}"
133 | ],
134 | "path": [
135 | "memory"
136 | ]
137 | }
138 | },
139 | "response": []
140 | },
141 | {
142 | "name": "memory",
143 | "event": [
144 | {
145 | "listen": "test",
146 | "script": {
147 | "exec": [
148 | "pm.test(\"Status test\", function () {",
149 | " pm.response.to.have.status(200);",
150 | "});",
151 | "",
152 | "pm.test(\"Content test\", () => {",
153 | " const responseJson = pm.response.json();",
154 | " pm.expect(responseJson.megabyte).to.eql(100);",
155 | " pm.expect(responseJson.duration).to.eql(15);",
156 | "});"
157 | ],
158 | "type": "text/javascript"
159 | }
160 | }
161 | ],
162 | "request": {
163 | "method": "PATCH",
164 | "header": [],
165 | "body": {
166 | "mode": "raw",
167 | "raw": "{\n \"megabyte\": 100,\n \"duration\": 15\n}",
168 | "options": {
169 | "raw": {
170 | "language": "json"
171 | }
172 | }
173 | },
174 | "url": {
175 | "raw": "{{baseUrl}}/memory",
176 | "host": [
177 | "{{baseUrl}}"
178 | ],
179 | "path": [
180 | "memory"
181 | ]
182 | }
183 | },
184 | "response": []
185 | }
186 | ]
187 | },
188 | {
189 | "name": "CPU",
190 | "item": [
191 | {
192 | "name": "cpu",
193 | "event": [
194 | {
195 | "listen": "test",
196 | "script": {
197 | "exec": [
198 | "pm.test(\"Status test\", function () {",
199 | " pm.response.to.have.status(200);",
200 | "});"
201 | ],
202 | "type": "text/javascript"
203 | }
204 | }
205 | ],
206 | "request": {
207 | "method": "GET",
208 | "header": [],
209 | "url": {
210 | "raw": "{{baseUrl}}/cpu",
211 | "host": [
212 | "{{baseUrl}}"
213 | ],
214 | "path": [
215 | "cpu"
216 | ]
217 | }
218 | },
219 | "response": []
220 | },
221 | {
222 | "name": "cpu",
223 | "event": [
224 | {
225 | "listen": "test",
226 | "script": {
227 | "exec": [
228 | "pm.test(\"Status test\", function () {",
229 | " pm.response.to.have.status(200);",
230 | "});",
231 | "",
232 | "pm.test(\"Content test\", () => {",
233 | " const responseJson = pm.response.json();",
234 | " pm.expect(responseJson.load).to.eql(5.7);",
235 | " pm.expect(responseJson.duration).to.eql(10);",
236 | " pm.expect(responseJson.core).to.eql(2);",
237 | "});"
238 | ],
239 | "type": "text/javascript"
240 | }
241 | }
242 | ],
243 | "request": {
244 | "method": "PATCH",
245 | "header": [],
246 | "body": {
247 | "mode": "raw",
248 | "raw": "{\n \"load\": 5.7,\n \"duration\": 10,\n \"core\": 2\n}",
249 | "options": {
250 | "raw": {
251 | "language": "json"
252 | }
253 | }
254 | },
255 | "url": {
256 | "raw": "{{baseUrl}}/cpu",
257 | "host": [
258 | "{{baseUrl}}"
259 | ],
260 | "path": [
261 | "cpu"
262 | ]
263 | }
264 | },
265 | "response": []
266 | }
267 | ]
268 | },
269 | {
270 | "name": "LogLevel",
271 | "item": [
272 | {
273 | "name": "log_level",
274 | "event": [
275 | {
276 | "listen": "test",
277 | "script": {
278 | "exec": [
279 | "pm.test(\"Status test\", function () {",
280 | " pm.response.to.have.status(200);",
281 | " });"
282 | ],
283 | "type": "text/javascript"
284 | }
285 | }
286 | ],
287 | "protocolProfileBehavior": {
288 | "disableBodyPruning": true
289 | },
290 | "request": {
291 | "method": "GET",
292 | "header": [],
293 | "body": {
294 | "mode": "raw",
295 | "raw": "",
296 | "options": {
297 | "raw": {
298 | "language": "json"
299 | }
300 | }
301 | },
302 | "url": {
303 | "raw": "{{baseUrl}}/log_level",
304 | "host": [
305 | "{{baseUrl}}"
306 | ],
307 | "path": [
308 | "log_level"
309 | ]
310 | }
311 | },
312 | "response": []
313 | },
314 | {
315 | "name": "log_level",
316 | "event": [
317 | {
318 | "listen": "test",
319 | "script": {
320 | "exec": [
321 | "pm.test(\"Status test\", function () {",
322 | " pm.response.to.have.status(200);",
323 | "});",
324 | "",
325 | "pm.test(\"Content test\", () => {",
326 | " const responseJson = pm.response.json();",
327 | " pm.expect(responseJson.level).to.eql(\"debug\");",
328 | "});"
329 | ],
330 | "type": "text/javascript"
331 | }
332 | }
333 | ],
334 | "request": {
335 | "method": "PATCH",
336 | "header": [],
337 | "body": {
338 | "mode": "raw",
339 | "raw": "{\n \"level\": \"debug\"\n}",
340 | "options": {
341 | "raw": {
342 | "language": "json"
343 | }
344 | }
345 | },
346 | "url": {
347 | "raw": "{{baseUrl}}/log_level",
348 | "host": [
349 | "{{baseUrl}}"
350 | ],
351 | "path": [
352 | "log_level"
353 | ]
354 | }
355 | },
356 | "response": []
357 | }
358 | ]
359 | },
360 | {
361 | "name": "State",
362 | "item": [
363 | {
364 | "name": "state",
365 | "event": [
366 | {
367 | "listen": "test",
368 | "script": {
369 | "exec": [
370 | "pm.test(\"Status test\", function () {",
371 | " pm.response.to.have.status(200);",
372 | "});",
373 | ""
374 | ],
375 | "type": "text/javascript"
376 | }
377 | }
378 | ],
379 | "request": {
380 | "method": "GET",
381 | "header": [],
382 | "url": {
383 | "raw": "{{baseUrl}}",
384 | "host": [
385 | "{{baseUrl}}"
386 | ],
387 | "path": [
388 | "/"
389 | ]
390 | }
391 | },
392 | "response": []
393 | },
394 | {
395 | "name": "state",
396 | "event": [
397 | {
398 | "listen": "test",
399 | "script": {
400 | "exec": [
401 | "pm.test(\"Status test\", function () {",
402 | " pm.response.to.have.status(200);",
403 | "});",
404 | "",
405 | "pm.test(\"Content test\", () => {",
406 | " const responseJson = pm.response.json();",
407 | " pm.expect(responseJson.cpu.load).to.eql(5.3);",
408 | " pm.expect(responseJson.cpu.duration).to.eql(11);",
409 | " pm.expect(responseJson.cpu.core).to.eql(1);",
410 | " pm.expect(responseJson.memory.megabyte).to.eql(70);",
411 | " pm.expect(responseJson.memory.duration).to.eql(2);",
412 | " pm.expect(responseJson.log_level.level).to.eql(\"debug\");",
413 | "});"
414 | ],
415 | "type": "text/javascript"
416 | }
417 | }
418 | ],
419 | "request": {
420 | "method": "PATCH",
421 | "header": [],
422 | "body": {
423 | "mode": "raw",
424 | "raw": "{\n \"memory\": {\n \"megabyte\": 70,\n \"duration\": 2\n },\n \"cpu\": {\n \"load\": 5.3,\n \"duration\": 11,\n \"core\": 1\n },\n \"log_level\": {\n \"level\": \"debug\"\n }\n}",
425 | "options": {
426 | "raw": {
427 | "language": "json"
428 | }
429 | }
430 | },
431 | "url": {
432 | "raw": "{{baseUrl}}",
433 | "host": [
434 | "{{baseUrl}}"
435 | ],
436 | "path": [
437 | "/"
438 | ]
439 | }
440 | },
441 | "response": []
442 | }
443 | ]
444 | }
445 | ]
446 | }
447 | ],
448 | "event": [
449 | {
450 | "listen": "prerequest",
451 | "script": {
452 | "type": "text/javascript",
453 | "exec": [
454 | ""
455 | ]
456 | }
457 | },
458 | {
459 | "listen": "test",
460 | "script": {
461 | "type": "text/javascript",
462 | "exec": [
463 | ""
464 | ]
465 | }
466 | }
467 | ],
468 | "variable": [
469 | {
470 | "key": "baseUrl",
471 | "value": "localhost:11000"
472 | }
473 | ]
474 | }
475 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | BIN := ${PWD}/bin
3 | export PATH := ${BIN}:${PATH}
4 |
5 | CUSTOM_FORMATS := formats/custom
6 |
7 | LICENSEI := ${BIN}/licensei
8 | LICENSEI_VERSION := v0.9.0
9 |
10 | HELM_DOCS := ${BIN}/helm-docs
11 | HELM_DOCS_VERSION = 1.14.2
12 |
13 | GOFLAGS =
14 |
15 | ${BIN}:
16 | mkdir -p ${BIN}
17 |
18 | .PHONY: license-check
19 | license-check: ${LICENSEI} ## Run license check
20 | ${LICENSEI} check
21 | ${LICENSEI} header
22 |
23 | .PHONY: license-cache
24 | license-cache: ${LICENSEI} go.work ## Generate license cache
25 | ${LICENSEI} cache
26 |
27 | .PHONY: check
28 | check:
29 | go fmt ./...
30 | go vet ./...
31 | cd log && $(MAKE) check
32 |
33 | go.work:
34 | go work init . log ${CUSTOM_FORMATS}
35 |
36 | .PHONY: reinit
37 | reinit:
38 | rm -f go.work
39 | @$(MAKE) go.work
40 |
41 | .PHONY: build
42 | build: go.work
43 | CGO_ENABLED=0 go build ${GOFLAGS} -a -o ${BIN}/loggen main.go
44 |
45 | .PHONY: test
46 | test: go.work
47 | go test ${GOFLAGS} ./...
48 | cd log && $(MAKE) test
49 |
50 | .PHONY: docker-run
51 | docker-run:
52 | docker build . -t log-generator:local && docker run -p 11000:11000 log-generator:local
53 |
54 | .PHONY: helm-docs
55 | helm-docs: ${HELM_DOCS}
56 | ${HELM_DOCS} -s file -c charts/ -t ../charts-docs/templates/overrides.gotmpl -t README.md.gotmpl
57 |
58 | .PHONY: check-diff
59 | check-diff: helm-docs check
60 | git diff --exit-code ':(exclude)./ADOPTERS.md' ':(exclude)./docs/*'
61 |
62 | .PHONY: tidy
63 | tidy: ## Tidy Go modules
64 | find . -iname "go.mod" -not -path "./.devcontainer/*" | xargs -L1 sh -c 'cd $$(dirname $$0); go mod tidy'
65 |
66 | ${LICENSEI}: ${LICENSEI}_${LICENSEI_VERSION} | ${BIN}
67 | ln -sf $(notdir $<) $@
68 |
69 | ${LICENSEI}_${LICENSEI_VERSION}: IMPORT_PATH := github.com/goph/licensei/cmd/licensei
70 | ${LICENSEI}_${LICENSEI_VERSION}: VERSION := ${LICENSEI_VERSION}
71 | ${LICENSEI}_${LICENSEI_VERSION}: | ${BIN}
72 | ${go_install_binary}
73 |
74 | ${HELM_DOCS}: ${HELM_DOCS}-${HELM_DOCS_VERSION}
75 | @ln -sf ${HELM_DOCS}-${HELM_DOCS_VERSION} ${HELM_DOCS}
76 | ${HELM_DOCS}-${HELM_DOCS_VERSION}:
77 | @mkdir -p bin
78 | curl -L https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS_VERSION}/helm-docs_${HELM_DOCS_VERSION}_$(shell uname)_x86_64.tar.gz | tar -zOxf - helm-docs > ${HELM_DOCS}-${HELM_DOCS_VERSION} && chmod +x ${HELM_DOCS}-${HELM_DOCS_VERSION}
79 |
80 | define go_install_binary
81 | find ${BIN} -name '$(notdir ${IMPORT_PATH})_*' -exec rm {} +
82 | GOBIN=${BIN} go install ${IMPORT_PATH}@${VERSION}
83 | mv ${BIN}/$(notdir ${IMPORT_PATH}) ${BIN}/$(notdir ${IMPORT_PATH})_${VERSION}
84 | endef
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Log-Generator
2 |
3 | API managed testing tool for logging-operator
4 |
5 | ## Deploy log-generator with Helm
6 |
7 | ```sh
8 | helm install --wait --generate-name oci://ghcr.io/kube-logging/helm-charts/log-generator
9 | ```
10 |
11 | ## Usage
12 |
13 | You can start the daemon serving the API on e.g. port 11000 by running the following command:
14 |
15 | ```sh
16 | go run main.go
17 | ```
18 |
19 | Now you can connect to from your browser or using your favorite HTTP client.
20 |
21 | ## Available API Calls
22 |
23 | ### Log generator
24 |
25 | #### [GET] /loggen
26 |
27 | Call:
28 |
29 | ```sh
30 | curl --location --request GET 'localhost:11000/loggen'
31 | ```
32 |
33 | Response:
34 |
35 | ```json
36 | {
37 | "event_per_sec": 100,
38 | "byte_per_sec": 200,
39 | "randomise": true,
40 | "active_requests": [],
41 | "golang_log": {
42 | "error_weight": 0,
43 | "warning_weight": 0,
44 | "info_weight": 1,
45 | "debug_weight": 0
46 | }
47 | }
48 | ```
49 |
50 | #### [GET] /loggen/formats
51 |
52 | Call:
53 |
54 | ```sh
55 | curl --location --request GET 'localhost:11000/loggen/formats'
56 | ```
57 |
58 | Response:
59 |
60 | ```json
61 | {
62 | "web": [
63 | "apache",
64 | "nginx"
65 | ]
66 | }
67 | ```
68 |
69 | #### [POST] /loggen
70 |
71 | Call:
72 |
73 | ```sh
74 | curl --location --request POST 'localhost:11000/loggen' \
75 | --header 'Content-Type: application/json' \
76 | --data-raw '{
77 | "type": "web",
78 | "format": "nginx",
79 | "count": 1000,
80 | "framing": false
81 | }'
82 | ```
83 |
84 | Response:
85 |
86 | ```json
87 | {
88 | "type": "web",
89 | "format": "nginx",
90 | "count": 1000,
91 | "framing": false
92 | }
93 | ```
94 |
95 | ### Manage Memory Load Function
96 |
97 | #### [GET] /memory
98 |
99 | Call:
100 |
101 | ```sh
102 | curl --location --request GET 'localhost:11000/memory'
103 | ```
104 |
105 | Response:
106 |
107 | ```json
108 | {
109 | "megabyte": 0,
110 | "active": "0001-01-01T00:00:00Z",
111 | "duration": 0,
112 | "last_modified": "0001-01-01T00:00:00Z"
113 | }
114 | ```
115 |
116 | #### [PATCH] /memory
117 |
118 | Call:
119 |
120 | ```sh
121 | curl --location --request PATCH 'localhost:11000/memory' \
122 | --header 'Content-Type: application/json' \
123 | --data-raw '{
124 | "megabyte": 100,
125 | "duration": 15
126 | }'
127 | ```
128 |
129 | Response:
130 |
131 | ```json
132 | {
133 | "megabyte": 100,
134 | "active": "2021-09-09T17:41:47.813508+02:00",
135 | "duration": 15,
136 | "last_modified": "2021-09-09T17:41:32.813508+02:00"
137 | }
138 | ```
139 |
140 | ### Manage CPU Load Function
141 |
142 | #### [GET] /cpu
143 |
144 | Call:
145 |
146 | ```sh
147 | curl --location --request GET 'localhost:11000/cpu'
148 | ```
149 |
150 | Response:
151 |
152 | ```json
153 | {
154 | "load": 0,
155 | "duration": 0,
156 | "active": "0001-01-01T00:00:00Z",
157 | "core": 0,
158 | "last_modified": "0001-01-01T00:00:00Z"
159 | }
160 |
161 | ```
162 |
163 | #### [PATCH] /cpu
164 |
165 | Call:
166 |
167 | ```sh
168 | curl --location --request PATCH 'localhost:11000/cpu' \
169 | --header 'Content-Type: application/json' \
170 | --data-raw '{
171 | "load": 5.7,
172 | "duration": 10,
173 | "core": 2
174 | }'
175 | ```
176 |
177 | Response:
178 |
179 | ```json
180 | {
181 | "load": 5.7,
182 | "duration": 10,
183 | "active": "2021-09-10T14:50:00.525809+02:00",
184 | "core": 2,
185 | "last_modified": "2021-09-10T14:49:50.525808+02:00"
186 | }
187 | ```
188 |
189 | ### Manage Log Level Configuration
190 |
191 | #### [GET] /log_level
192 |
193 | Call:
194 |
195 | ```sh
196 | curl --location --request GET 'localhost:11000/log_level'
197 | ```
198 |
199 | Response:
200 |
201 | ```json
202 | {
203 | "level": "debug",
204 | "last_modified": "0001-01-01T00:00:00Z"
205 | }
206 |
207 | ```
208 |
209 | #### [PATCH] /log_level
210 |
211 | Call:
212 |
213 | ```sh
214 | curl --location --request PATCH 'localhost:11000/log_level' \
215 | --header 'Content-Type: application/json' \
216 | --data-raw '{
217 | "level": "info"
218 | }'
219 | ```
220 |
221 | Response:
222 |
223 | ```json
224 | {
225 | "level": "info",
226 | "last_modified": "2021-09-10T14:51:56.639658+02:00"
227 | }
228 | ```
229 |
230 | ### Status
231 |
232 | #### [GET] /
233 |
234 | Call:
235 |
236 | ```sh
237 | curl --location --request GET 'localhost:11000/'
238 | ```
239 |
240 | Response:
241 |
242 | ```json
243 | {
244 | "memory": {
245 | "megabyte": 0,
246 | "active": "0001-01-01T00:00:00Z",
247 | "duration": 0,
248 | "last_modified": "0001-01-01T00:00:00Z"
249 | },
250 | "cpu": {
251 | "load": 5.7,
252 | "duration": 10,
253 | "active": "2021-09-10T14:50:00.525809+02:00",
254 | "core": 2,
255 | "last_modified": "2021-09-10T14:49:50.525808+02:00"
256 | },
257 | "log_level": {
258 | "level": "info",
259 | "last_modified": "2021-09-10T14:51:56.639658+02:00"
260 | }
261 | }
262 | ```
263 |
264 | #### [PATCH] /
265 |
266 | Call:
267 |
268 | ```sh
269 | curl --location --request PATCH 'localhost:11000/' \
270 | --header 'Content-Type: application/json' \
271 | --data-raw '{
272 | "memory": {
273 | "megabyte": 70,
274 | "duration": 2
275 | },
276 | "cpu": {
277 | "load": 5.3,
278 | "duration": 11,
279 | "core": 1
280 | },
281 | "log_level": {
282 | "level": "debug"
283 | }
284 | }'
285 | ```
286 |
287 | Response:
288 |
289 | ```json
290 | {
291 | "memory": {
292 | "megabyte": 70,
293 | "active": "2021-09-10T14:53:42.425137+02:00",
294 | "duration": 2,
295 | "last_modified": "2021-09-10T14:53:40.425137+02:00"
296 | },
297 | "cpu": {
298 | "load": 5.3,
299 | "duration": 11,
300 | "active": "2021-09-10T14:53:51.42514+02:00",
301 | "core": 1,
302 | "last_modified": "2021-09-10T14:53:40.42514+02:00"
303 | },
304 | "log_level": {
305 | "level": "debug",
306 | "last_modified": "2021-09-10T14:53:40.425195+02:00"
307 | }
308 | }
309 | ```
310 |
311 | ## Testing with newman
312 |
313 | Install [newman](https://github.com/postmanlabs/newman) with homebrew
314 |
315 | ```sh
316 | brew install newman
317 | ```
318 |
319 | Run the collection test
320 |
321 | ```sh
322 | newman run Log-Generator.postman_collection.json --env-var "baseUrl=localhost:11000"
323 | ```
324 |
325 | Expected Output:
326 |
327 | ```sh
328 | Log-Generator
329 |
330 | ❏ Test / Loggen
331 | ↳ loggen
332 | GET localhost:11000/loggen [200 OK, 284B, 31ms]
333 | ✓ Status test
334 |
335 | ↳ loggen
336 | POST localhost:11000/loggen [200 OK, 171B, 7ms]
337 | ✓ Status test
338 | ✓ Content test
339 |
340 | ❏ Test / Memory
341 | ↳ memory
342 | GET localhost:11000/memory [200 OK, 221B, 5ms]
343 | ✓ Status test
344 |
345 | ↳ memory
346 | PATCH localhost:11000/memory [200 OK, 255B, 3ms]
347 | ✓ Status test
348 | ✓ Content test
349 |
350 | ❏ Test / CPU
351 | ↳ cpu
352 | GET localhost:11000/cpu [200 OK, 227B, 4ms]
353 | ✓ Status test
354 |
355 | ↳ cpu
356 | PATCH localhost:11000/cpu [200 OK, 260B, 3ms]
357 | ✓ Status test
358 | ✓ Content test
359 |
360 | ❏ Test / LogLevel
361 | ↳ log_level
362 | GET localhost:11000/log_level [200 OK, 179B, 3ms]
363 | ✓ Status test
364 |
365 | ↳ log_level
366 | PATCH localhost:11000/log_level [200 OK, 194B, 3ms]
367 | ✓ Status test
368 | ✓ Content test
369 |
370 | ❏ Test / State
371 | ↳ state
372 | GET localhost:11000// [200 OK, 711B, 5ms]
373 | ✓ Status test
374 |
375 | ↳ state
376 | PATCH localhost:11000// [200 OK, 708B, 4ms]
377 | ✓ Status test
378 | ✓ Content test
379 |
380 | ┌─────────────────────────┬─────────────────┬─────────────────┐
381 | │ │ executed │ failed │
382 | ├─────────────────────────┼─────────────────┼─────────────────┤
383 | │ iterations │ 1 │ 0 │
384 | ├─────────────────────────┼─────────────────┼─────────────────┤
385 | │ requests │ 10 │ 0 │
386 | ├─────────────────────────┼─────────────────┼─────────────────┤
387 | │ test-scripts │ 20 │ 0 │
388 | ├─────────────────────────┼─────────────────┼─────────────────┤
389 | │ prerequest-scripts │ 10 │ 0 │
390 | ├─────────────────────────┼─────────────────┼─────────────────┤
391 | │ assertions │ 15 │ 0 │
392 | ├─────────────────────────┴─────────────────┴─────────────────┤
393 | │ total run duration: 280ms │
394 | ├─────────────────────────────────────────────────────────────┤
395 | │ total data received: 1.97kB (approx) │
396 | ├─────────────────────────────────────────────────────────────┤
397 | │ average response time: 6ms [min: 3ms, max: 31ms, s.d.: 8ms] │
398 | └─────────────────────────────────────────────────────────────┘
399 | ```
400 |
--------------------------------------------------------------------------------
/charts-docs/README.md:
--------------------------------------------------------------------------------
1 | # Helm chart documentation
2 |
3 | README files for Helm charts are generated using [helm-docs](https://github.com/norwoodj/helm-docs).
4 |
5 | Each chart should contain a `README.md.gotmpl` file that describes how
6 | the `README.md` of the chart should be generated.
7 |
8 | Normally, this file can be the same as the primary template in [docs/templates/README.md.gotmpl] or a symlink pointing to it:
9 |
10 | ```bash
11 | cd charts/CHART
12 | ln -s ../../docs/templates/README.md.gotmpl
13 | ```
14 |
15 | Copy the file to the chart directory if you want to customize the template.
16 |
17 | **Note:** Don't forget to add `README.md.gotmpl` to `.helmignore`.
18 |
19 | Then run `make docs` in the repository root.
20 |
--------------------------------------------------------------------------------
/charts-docs/templates/README.md.gotmpl:
--------------------------------------------------------------------------------
1 | {{ template "chart.header" . }}
2 |
3 | {{ template "chart.versionBadge" . }} {{ template "chart.typeBadge" . }} {{ template "chart.appVersionBadge" . }} {{ template "chart.kubeVersionBadge" . }} {{ template "chart.artifactHubBadge" . }}
4 |
5 | {{ template "chart.description" . }}
6 |
7 | {{ template "chart.homepageLine" . }}
8 |
9 | {{ template "tldr" . }}
10 |
11 | {{ template "chart.valuesSection" . }}
12 |
--------------------------------------------------------------------------------
/charts-docs/templates/overrides.gotmpl:
--------------------------------------------------------------------------------
1 | {{- define "chart.typeBadge" -}}
2 | {{- if .Type -}}{{- end -}}
3 | {{- end -}}
4 |
5 | {{- define "chart.artifactHubBadge" -}}
6 | [](https://artifacthub.io/packages/helm/kube-logging/{{ .Name }})
7 | {{- end -}}
8 |
9 | {{- define "tldr" -}}
10 | ## TL;DR;
11 |
12 | ```bash
13 | helm install --wait --generate-name oci://ghcr.io/kube-logging/helm-charts/{{ .Name }}
14 | ```
15 | {{- end -}}
16 |
17 | {{- define "chart.badges" -}}
18 | {{ template "chart.versionBadge" . }} {{ template "chart.typeBadge" . }} {{ template "chart.appVersionBadge" . }} {{ template "chart.kubeVersionBadge" . }} {{ template "chart.artifactHubBadge" . }}
19 | {{- end -}}
20 |
21 | {{- define "chart.baseHead" -}}
22 | {{ template "chart.header" . }}
23 |
24 | {{ template "chart.badges" . }}
25 |
26 | {{ template "chart.description" . }}
27 |
28 | {{ template "chart.homepageLine" . }}
29 |
30 | {{ template "tldr" . }}
31 | {{- end -}}
32 |
33 | {{- define "chart.base" -}}
34 | {{ template "chart.baseHead" . }}
35 |
36 | {{ template "chart.valuesSection" . }}
37 | {{- end -}}
38 |
--------------------------------------------------------------------------------
/charts/log-generator/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
25 | ci/
26 | README.md.gotmpl
27 |
--------------------------------------------------------------------------------
/charts/log-generator/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | type: application
3 | name: log-generator
4 | version: 0.0.0
5 | appVersion: latest
6 | kubeVersion: ">=1.22.0-0"
7 | description: A Helm chart for Log-generator
8 | keywords:
9 | - logging
10 | home: https://kube-logging.github.io
11 | sources:
12 | - https://github.com/kube-logging/log-generator
13 |
--------------------------------------------------------------------------------
/charts/log-generator/README.md:
--------------------------------------------------------------------------------
1 | # log-generator
2 |
3 | A Helm chart for Log-generator
4 |
5 | **Homepage:**
6 |
7 | ## TL;DR;
8 |
9 | ```bash
10 | helm install --wait --generate-name oci://ghcr.io/kube-logging/helm-charts/log-generator
11 | ```
12 |
13 | ## Values
14 |
15 | | Key | Type | Default | Description |
16 | |-----|------|---------|-------------|
17 | | replicaCount | int | `1` | |
18 | | image.repository | string | `"ghcr.io/kube-logging/log-generator"` | |
19 | | image.tag | string | `""` | |
20 | | image.pullPolicy | string | `"IfNotPresent"` | |
21 | | imagePullSecrets | list | `[]` | |
22 | | nameOverride | string | `""` | |
23 | | fullnameOverride | string | `""` | |
24 | | serviceAccount.create | bool | `true` | |
25 | | serviceAccount.name | string | `nil` | |
26 | | podSecurityContext | object | `{}` | |
27 | | securityContext | object | `{}` | |
28 | | app.minInterval | int | `100` | |
29 | | app.maxInterval | int | `1` | |
30 | | app.count | int | `-1` | |
31 | | app.randomise | bool | `true` | |
32 | | app.eventPerSec | int | `1` | |
33 | | app.bytePerSec | int | `0` | |
34 | | app.golang | bool | `false` | |
35 | | app.nginx | bool | `true` | |
36 | | app.apache | bool | `false` | |
37 | | api.addr | string | `"11000"` | |
38 | | api.serviceName | string | `"log-generator-api"` | |
39 | | api.basePath | string | `"/"` | |
40 | | api.serviceMonitor.enabled | bool | `false` | |
41 | | api.serviceMonitor.additionalLabels | object | `{}` | |
42 | | api.serviceMonitor.namespace | string | `nil` | |
43 | | api.serviceMonitor.interval | string | `nil` | |
44 | | api.serviceMonitor.scrapeTimeout | string | `nil` | |
45 | | resources | object | `{}` | |
46 | | nodeSelector | object | `{}` | |
47 | | tolerations | list | `[]` | |
48 | | affinity | object | `{}` | |
49 | | topologySpreadConstraints | list | `[]` | |
50 |
--------------------------------------------------------------------------------
/charts/log-generator/README.md.gotmpl:
--------------------------------------------------------------------------------
1 | {{ template "chart.header" . }}
2 |
3 | {{ template "chart.description" . }}
4 |
5 | {{ template "chart.homepageLine" . }}
6 |
7 | {{ template "tldr" . }}
8 |
9 | {{ template "chart.valuesSection" . }}
10 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/NOTES.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kube-logging/log-generator/a42e8917a5508fab28d5b7c571c06b354adf9bce/charts/log-generator/templates/NOTES.txt
--------------------------------------------------------------------------------
/charts/log-generator/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "log-generator.name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | If release name contains chart name it will be used as a full name.
13 | */}}
14 | {{- define "log-generator.fullname" -}}
15 | {{- if .Values.fullnameOverride -}}
16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17 | {{- else -}}
18 | {{- $name := default .Chart.Name .Values.nameOverride -}}
19 | {{- if contains $name .Release.Name -}}
20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21 | {{- else -}}
22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23 | {{- end -}}
24 | {{- end -}}
25 | {{- end -}}
26 |
27 | {{/*
28 | Create chart name and version as used by the chart label.
29 | */}}
30 | {{- define "log-generator.chart" -}}
31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
32 | {{- end -}}
33 |
34 | {{/*
35 | Common labels
36 | */}}
37 | {{- define "log-generator.labels" -}}
38 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
39 | helm.sh/chart: {{ include "log-generator.chart" . }}
40 | app.kubernetes.io/instance: {{ .Release.Name }}
41 | {{- if .Chart.AppVersion }}
42 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
43 | {{- end }}
44 | app.kubernetes.io/managed-by: {{ .Release.Service }}
45 | {{- end -}}
46 |
47 | {{/*
48 | Create the name of the service account to use
49 | */}}
50 | {{- define "log-generator.serviceAccountName" -}}
51 | {{- if .Values.serviceAccount.create -}}
52 | {{ default (include "log-generator.fullname" .) .Values.serviceAccount.name }}
53 | {{- else -}}
54 | {{ default "default" .Values.serviceAccount.name }}
55 | {{- end -}}
56 | {{- end -}}
57 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: {{ include "log-generator.fullname" . }}
5 | data:
6 | config.toml: |-
7 | [logging]
8 | level = "debug"
9 |
10 | [message]
11 | # The amount of log message to emit. (default: 0, -1 for generating messages indefinitely)
12 | count = {{ .Values.app.count }}
13 |
14 | # Randomise log content (default: true)
15 | randomise = {{ .Values.app.randomise }}
16 |
17 | # The amount of log message to emit/s (default: 4)
18 | event-per-sec = {{ .Values.app.eventPerSec }}
19 |
20 | # The amount of bytes to emit/s (default: 0)
21 | byte-per-sec = {{ .Values.app.bytePerSec }}
22 |
23 | [api]
24 | # Metrics server listen address (default: ":11000")
25 | addr = ":{{ .Values.api.addr }}"
26 | basePath = "{{ .Values.api.basePath }}"
27 |
28 | [golang]
29 | enabled = {{ .Values.app.golang }}
30 |
31 | [nginx]
32 | enabled = {{ .Values.app.nginx }}
33 |
34 | [apache]
35 | enabled = {{ .Values.app.apache }}
36 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: {{ include "log-generator.fullname" . }}
5 | labels:
6 | {{ include "log-generator.labels" . | indent 4 }}
7 | spec:
8 | replicas: {{ .Values.replicaCount }}
9 | selector:
10 | matchLabels:
11 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
12 | app.kubernetes.io/instance: {{ .Release.Name }}
13 | template:
14 | metadata:
15 | labels:
16 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
17 | app.kubernetes.io/instance: {{ .Release.Name }}
18 | spec:
19 | {{- with .Values.imagePullSecrets }}
20 | imagePullSecrets:
21 | {{- toYaml . | nindent 8 }}
22 | {{- end }}
23 | serviceAccountName: {{ template "log-generator.serviceAccountName" . }}
24 | securityContext:
25 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
26 | containers:
27 | - name: {{ .Chart.Name }}
28 | securityContext:
29 | {{- toYaml .Values.securityContext | nindent 12 }}
30 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
31 | imagePullPolicy: {{ .Values.image.pullPolicy }}
32 | command:
33 | - /loggen
34 | ports:
35 | - name: api
36 | containerPort: {{ .Values.api.addr }}
37 | protocol: TCP
38 | resources:
39 | {{- toYaml .Values.resources | nindent 12 }}
40 | volumeMounts:
41 | - name: config
42 | mountPath: /conf/config.toml
43 | subPath: config.toml
44 | volumes:
45 | - name: config
46 | configMap:
47 | name: {{ include "log-generator.fullname" . }}
48 | {{- with .Values.nodeSelector }}
49 | nodeSelector:
50 | {{- toYaml . | nindent 8 }}
51 | {{- end }}
52 | {{- with .Values.affinity }}
53 | affinity:
54 | {{- toYaml . | nindent 8 }}
55 | {{- end }}
56 | {{- with .Values.tolerations }}
57 | tolerations:
58 | {{- toYaml . | nindent 8 }}
59 | {{- end }}
60 | {{- with .Values.topologySpreadConstraints }}
61 | topologySpreadConstraints:
62 | {{- toYaml . | nindent 8 }}
63 | {{- end }}
64 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ .Values.api.serviceName }}
5 | labels:
6 | {{ include "log-generator.labels" . | indent 4 }}
7 | spec:
8 | type: ClusterIP
9 | ports:
10 | - port: {{ .Values.api.addr }}
11 | targetPort: api
12 | protocol: TCP
13 | name: api
14 | selector:
15 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
16 | app.kubernetes.io/instance: {{ .Release.Name }}
17 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ template "log-generator.serviceAccountName" . }}
6 | labels:
7 | {{ include "log-generator.labels" . | indent 4 }}
8 | {{- end -}}
9 |
--------------------------------------------------------------------------------
/charts/log-generator/templates/servicemonitor.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.api.serviceMonitor.enabled }}
2 | apiVersion: monitoring.coreos.com/v1
3 | kind: ServiceMonitor
4 | metadata:
5 | name: {{ include "log-generator.fullname" . }}-metrics
6 | {{- if .Values.api.serviceMonitor.namespace }}
7 | namespace: {{ .Values.api.serviceMonitor.namespace }}
8 | {{- end }}
9 | labels:
10 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | {{- if .Values.api.serviceMonitor.additionalLabels }}
13 | {{ toYaml .Values.api.serviceMonitor.additionalLabels | indent 4 }}
14 | {{- end }}
15 | spec:
16 | endpoints:
17 | - port: api
18 | {{- if .Values.api.serviceMonitor.interval }}
19 | interval: {{ .Values.api.serviceMonitor.interval }}
20 | {{- end }}
21 | {{- if .Values.api.serviceMonitor.scrapeTimeout }}
22 | scrapeTimeout: {{ .Values.api.serviceMonitor.scrapeTimeout }}
23 | {{- end }}
24 | namespaceSelector:
25 | matchNames:
26 | - {{ .Release.Namespace }}
27 | selector:
28 | matchLabels:
29 | app.kubernetes.io/name: {{ include "log-generator.name" . }}
30 | app.kubernetes.io/instance: {{ .Release.Name }}
31 |
32 | {{- end }}
33 |
34 |
--------------------------------------------------------------------------------
/charts/log-generator/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for log-generator.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 |
5 | replicaCount: 1
6 |
7 | image:
8 | repository: ghcr.io/kube-logging/log-generator
9 | # set tag to override default appVersion
10 | tag: ""
11 | pullPolicy: IfNotPresent
12 |
13 | imagePullSecrets: []
14 | nameOverride: ""
15 | fullnameOverride: ""
16 |
17 | serviceAccount:
18 | # Specifies whether a service account should be created
19 | create: true
20 | # The name of the service account to use.
21 | # If not set and create is true, a name is generated using the fullname template
22 | name:
23 |
24 | podSecurityContext: {}
25 | # fsGroup: 2000
26 |
27 | securityContext: {}
28 | # capabilities:
29 | # drop:
30 | # - ALL
31 | # readOnlyRootFilesystem: true
32 | # runAsNonRoot: true
33 | # runAsUser: 1000
34 |
35 | app:
36 | # Minimum interval between log messages (ms) (Default: 100)
37 | minInterval: 100
38 | # minInterval: 100
39 | # Maximum interval between log messages (s) (Default: 1)
40 | maxInterval: 1
41 | # maxInterval: 1
42 | # The amount of log message to emit. (Default: 0, -1 to generate logs indefinitely)
43 | count: -1
44 | # Randomise log content (Default: true)
45 | randomise: true
46 | # The amount of log message to emit/s (Default: 1)
47 | eventPerSec: 1
48 | # The amount of bytes to emit/s (Default: 0)
49 | bytePerSec: 0
50 | golang: false
51 | nginx: true
52 | apache: false
53 |
54 | api:
55 | # API server listen address (Default: "11000")
56 | addr: "11000"
57 | serviceName: "log-generator-api"
58 | basePath: "/"
59 | serviceMonitor:
60 | enabled: false
61 | additionalLabels: {}
62 | namespace:
63 | interval:
64 | scrapeTimeout:
65 | # namespace: monitoring
66 | # interval: 30s
67 | # scrapeTimeout: 10s
68 |
69 | resources: {}
70 | # We usually recommend not to specify default resources and to leave this as a conscious
71 | # choice for the user. This also increases chances charts run on environments with little
72 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
73 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
74 | # limits:
75 | # cpu: 100m
76 | # memory: 128Mi
77 | # requests:
78 | # cpu: 100m
79 | # memory: 128Mi
80 |
81 | nodeSelector: {}
82 |
83 | tolerations: []
84 |
85 | affinity: {}
86 |
87 | topologySpreadConstraints: []
88 |
--------------------------------------------------------------------------------
/conf/config.ini.sample:
--------------------------------------------------------------------------------
1 | [logging]
2 | #level = "debug"
3 |
4 | [message]
5 | # The amount of log message to emit. (default: 0) -1 to emit logs indefinitely.
6 | # count =
7 |
8 | # Randomise log content (default: true)
9 | # randomise =
10 |
11 | # The amount of log message to emit/s (default: 2)
12 | #event-per-sec =
13 |
14 | # The amount of bytes to emit/s (default: 200)
15 | #byte-per-sec =
16 |
17 | # Number of different random host names to generate
18 | #max-random-hosts = 1000
19 | # Number of different app names to generate
20 | #max-random-apps = 100
21 | # Random seed for host/app list generation so that the same set of host/app names are used (if >0)
22 | #seed = 0
23 |
24 | [api]
25 | # Server listen address (default: "":11000")
26 | #addr =
27 | # default: "/"
28 | #basePath =
29 |
30 | #[nginx]
31 | #enabled = true
32 |
33 | #[destination]
34 | #network = "tcp"
35 | #address = "127.0.0.1:514"
36 |
--------------------------------------------------------------------------------
/conf/configuration.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2021 Cisco Systems, Inc. and/or its affiliates
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package conf
16 |
17 | import (
18 | "fmt"
19 |
20 | "github.com/go-viper/encoding/ini"
21 | log "github.com/sirupsen/logrus"
22 | "github.com/spf13/viper"
23 | )
24 |
25 | var Viper *viper.Viper
26 |
27 | func Init() {
28 | codecRegistry := viper.NewCodecRegistry()
29 | codecRegistry.RegisterCodec("ini", &ini.Codec{})
30 | Viper = viper.NewWithOptions(
31 | viper.WithCodecRegistry(codecRegistry),
32 | )
33 | Viper.SetConfigName("config")
34 | Viper.SetConfigType("ini")
35 | Viper.AddConfigPath("./conf/")
36 |
37 | if err := Viper.ReadInConfig(); err != nil {
38 | log.Warnf("Error reading config file, %s", err)
39 | }
40 |
41 | Viper.SetDefault("logging.level", "info")
42 |
43 | level, lErr := log.ParseLevel(Viper.GetString("logging.level"))
44 | if lErr != nil {
45 | panic("unrecognized loglevel")
46 | }
47 | log.SetLevel(level)
48 |
49 | fmt.Printf("Using config: %s\n", Viper.ConfigFileUsed())
50 | Viper.SetDefault("message.count", 0)
51 | Viper.SetDefault("message.randomise", true)
52 | Viper.SetDefault("message.event-per-sec", 2)
53 | Viper.SetDefault("message.byte-per-sec", 200)
54 | Viper.SetDefault("message.max-random-hosts", 1000)
55 | Viper.SetDefault("message.max-random-apps", 100)
56 | Viper.SetDefault("message.host", "hostname")
57 | Viper.SetDefault("message.appname", "appname")
58 |
59 | Viper.SetDefault("api.addr", ":11000")
60 | Viper.SetDefault("api.basePath", "/")
61 |
62 | Viper.SetDefault("nginx.enabled", false)
63 | Viper.SetDefault("apache.enabled", false)
64 | Viper.SetDefault("golang.enabled", false)
65 | Viper.SetDefault("golang.time_format", "02/Jan/2006:15:04:05 -0700")
66 | Viper.SetDefault("golang.weight.error", 0)
67 | Viper.SetDefault("golang.weight.info", 1)
68 | Viper.SetDefault("golang.weight.warning", 0)
69 | Viper.SetDefault("golang.weight.debug", 0)
70 | }
71 |
--------------------------------------------------------------------------------
/formats/custom/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/kube-logging/log-generator/formats/custom
2 |
3 | go 1.23.6
4 |
5 | require github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b
6 |
7 | require (
8 | github.com/beorn7/perks v1.0.1 // indirect
9 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
10 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
11 | github.com/prometheus/client_golang v1.20.5 // indirect
12 | github.com/prometheus/client_model v0.6.1 // indirect
13 | github.com/prometheus/common v0.62.0 // indirect
14 | github.com/prometheus/procfs v0.15.1 // indirect
15 | github.com/sirupsen/logrus v1.9.3 // indirect
16 | golang.org/x/sys v0.30.0 // indirect
17 | google.golang.org/protobuf v1.36.5 // indirect
18 | )
19 |
--------------------------------------------------------------------------------
/formats/custom/go.sum:
--------------------------------------------------------------------------------
1 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
9 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
10 | github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
11 | github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
12 | github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b h1:qeGOor3k0POAnVkTlno/AXf71lefey7CS9SD03QIcfA=
13 | github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b/go.mod h1:+ZQ22F6eQ1BAkfzKa85LS2XuKgqBEgVOnJVmlP97yls=
14 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
15 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18 | github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
19 | github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
20 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
21 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
22 | github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
23 | github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
24 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
25 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
26 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
27 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
28 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
29 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
30 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
31 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
32 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
33 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
34 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
35 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
36 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
37 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
38 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
39 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
40 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
41 |
--------------------------------------------------------------------------------
/formats/custom/stub.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package custom
16 |
17 | import (
18 | "github.com/kube-logging/log-generator/log"
19 | )
20 |
21 | // Formats returns supported template formats for a given type
22 | func Formats() map[string][]string {
23 | return map[string][]string{}
24 | }
25 |
26 | // LogFactory creates log events for a log format and optionally randomises it
27 | func LogFactory(logType string, format string, randomise bool) (log.Log, error) {
28 | return nil, nil
29 | }
30 |
--------------------------------------------------------------------------------
/formats/golang/golang.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2021 Cisco Systems, Inc. and/or its affiliates
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package golang
16 |
17 | import (
18 | "bytes"
19 | "encoding/json"
20 | "fmt"
21 | "math/rand"
22 | "time"
23 |
24 | "github.com/Pallinder/go-randomdata"
25 | wr "github.com/mroth/weightedrand"
26 | "github.com/prometheus/client_golang/prometheus"
27 | log "github.com/sirupsen/logrus"
28 |
29 | "github.com/kube-logging/log-generator/conf"
30 | )
31 |
32 | type GolangLogIntensity struct {
33 | ErrorWeight *uint `json:"error_weight"`
34 | WarningWeight *uint `json:"warning_weight"`
35 | InfoWeight *uint `json:"info_weight"`
36 | DebugWeight *uint `json:"debug_weight"`
37 | }
38 |
39 | type GolangLog struct {
40 | Application string `json:"application"`
41 | Environment string `json:"environment"`
42 | Component string `json:"component"`
43 | Level string `json:"level"`
44 | MSG string `json:"msg"`
45 | Time string `json:"time"`
46 |
47 | isFramed bool
48 | }
49 |
50 | func (g GolangLog) newRandomMessage() string {
51 | msgList := map[string]string{
52 | "info": randomdata.StringSample(
53 | "constructing many client instances from the same exec auth config can cause performance problems during cert rotation and can exhaust available network connections; 1083 clients constructed calling",
54 | "starting posthook function",
55 | "rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRole\\n",
56 | ),
57 | "warning": randomdata.StringSample(
58 | "no security scan whitelist information available...",
59 | "firewall is still alive",
60 | "apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition",
61 | ),
62 | "error": randomdata.StringSample(
63 | "could not get cluster from database: could not find cluster by ID: cluster not found",
64 | "Activity error.",
65 | "converting cluster model to common cluster failed: record not found",
66 | ),
67 | }
68 | return msgList[g.Level]
69 | }
70 |
71 | func NewGolangLogRandom(i GolangLogIntensity) *GolangLog {
72 | rand.Seed(time.Now().UTC().UnixNano())
73 | c, err := wr.NewChooser(
74 | wr.Choice{Item: "error", Weight: *i.ErrorWeight},
75 | wr.Choice{Item: "warning", Weight: *i.WarningWeight},
76 | wr.Choice{Item: "info", Weight: *i.InfoWeight},
77 | wr.Choice{Item: "debug", Weight: *i.DebugWeight},
78 | )
79 | if err != nil {
80 | log.Error(err)
81 | }
82 | return &GolangLog{
83 | Application: randomdata.StringSample("webshop", "blog"),
84 | Environment: randomdata.StringSample("production", "sandbox", "demo"),
85 | Component: randomdata.StringSample("frontend", "backend", "worker"),
86 | Level: c.Pick().(string),
87 | Time: "",
88 | }
89 | }
90 |
91 | func (g GolangLog) String() (string, float64) {
92 | g.Time = time.Now().Format(conf.Viper.GetString("golang.time_format"))
93 | g.MSG = g.newRandomMessage()
94 |
95 | out, err := json.MarshalIndent(g, "", " ")
96 | if err != nil {
97 | log.Error(err)
98 | }
99 |
100 | buffer := new(bytes.Buffer)
101 | if err := json.Compact(buffer, out); err != nil {
102 | log.Error(err)
103 | }
104 |
105 | message := fmt.Sprint(buffer.String())
106 |
107 | return message, float64(len([]byte(message)))
108 | }
109 |
110 | func (l *GolangLog) IsFramed() bool {
111 | return l.isFramed
112 | }
113 |
114 | func (l *GolangLog) SetFramed(f bool) {
115 | l.isFramed = f
116 | }
117 |
118 | func (g GolangLog) Labels() prometheus.Labels {
119 | return prometheus.Labels{
120 | "type": "golang",
121 | "severity": g.Level,
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/formats/logfactory.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package formats
16 |
17 | import (
18 | "embed"
19 |
20 | "github.com/kube-logging/log-generator/formats/custom"
21 | "github.com/kube-logging/log-generator/formats/golang"
22 | "github.com/kube-logging/log-generator/formats/web"
23 | "github.com/kube-logging/log-generator/log"
24 | )
25 |
26 | func FormatsByType() map[string][]string {
27 | response := map[string][]string{}
28 | for t, f := range custom.Formats() {
29 | response[t] = f
30 | }
31 | response["web"] = WebFormatNames()
32 | return response
33 | }
34 |
35 | func LogFactory(logType string, format string, randomise bool) (log.Log, error) {
36 | switch logType {
37 | case "web":
38 | if randomise {
39 | return NewRandomWeb(format, web.TemplateFS)
40 | } else {
41 | return NewWeb(format, web.TemplateFS)
42 | }
43 | default:
44 | return custom.LogFactory(logType, format, randomise)
45 | }
46 | }
47 |
48 | func NewWeb(format string, templates embed.FS) (*log.LogTemplate, error) {
49 | return log.NewLogTemplate(format, templates, web.SampleData())
50 | }
51 |
52 | func NewRandomWeb(format string, templates embed.FS) (*log.LogTemplate, error) {
53 | return log.NewLogTemplate(format, templates, web.RandomData())
54 | }
55 |
56 | func WebFormatNames() []string {
57 | return log.FormatNames(web.TemplateFS)
58 | }
59 |
60 | func NewGolangRandom(i golang.GolangLogIntensity) log.Log {
61 | return golang.NewGolangLogRandom(i)
62 | }
63 |
--------------------------------------------------------------------------------
/formats/logfactory_test.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package formats
16 |
17 | import (
18 | "embed"
19 | "strings"
20 | "testing"
21 |
22 | "github.com/kube-logging/log-generator/formats/web"
23 | "github.com/kube-logging/log-generator/log"
24 | )
25 |
26 | type LogConstructor func(string, embed.FS) (*log.LogTemplate, error)
27 |
28 | func TestWebFormats(t *testing.T) {
29 | // Separate Template tree per directory because Go Template can not handle
30 | // multiple files with the same name in different directories.
31 | assertFormatAll(t, web.TemplateFS, NewWeb)
32 | }
33 |
34 | func assertFormatAll(t *testing.T, embeddedTemplates embed.FS, c LogConstructor) {
35 | templates := log.LoadAllTemplates(embeddedTemplates)
36 | for _, f := range templates {
37 | format := strings.TrimSuffix(f.Name(), ".tmpl")
38 | log, err := c(format, embeddedTemplates)
39 | if err != nil {
40 | t.Fatalf("Failed to create log, format=%q, %v", format, err)
41 | }
42 |
43 | if l, _ := log.String(); len(strings.TrimSpace(l)) == 0 {
44 | t.Logf("Rendered log is empty, format=%q", format)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/formats/web/apache.tmpl:
--------------------------------------------------------------------------------
1 | {{.Remote}} {{.Host}} {{.User}} [{{.WebServerDateTime}}] {{.User}} "{{.Method}} {{.Path}} HTTP/1.1" {{.Code}} {{.Size}} "{{.Referer}}" "{{.Agent}}" "{{.HttpXForwardedFor}}"
2 |
--------------------------------------------------------------------------------
/formats/web/nginx.tmpl:
--------------------------------------------------------------------------------
1 | {{.Remote}} {{.Host}} {{.User}} [{{.WebServerDateTime}}] "{{.Method}} {{.Path}} HTTP/1.1" {{.Code}} {{.Size}} "{{.Referer}}" "{{.Agent}}" "{{.HttpXForwardedFor}}"
2 |
--------------------------------------------------------------------------------
/formats/web/web.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package web
16 |
17 | import (
18 | "embed"
19 | "math/rand"
20 | "strconv"
21 | "time"
22 |
23 | "github.com/Pallinder/go-randomdata"
24 |
25 | wr "github.com/mroth/weightedrand"
26 | )
27 |
28 | //go:embed *.tmpl
29 | var TemplateFS embed.FS
30 |
31 | type TemplateData struct {
32 | Remote string
33 | Host string
34 | User string
35 | Time time.Time
36 | Method string
37 | Path string
38 | Code int
39 | Size int
40 | Referer string
41 | Agent string
42 | HttpXForwardedFor string
43 | }
44 |
45 | func SampleData() TemplateData {
46 | return TemplateData{
47 | Remote: "127.0.0.1",
48 | Host: "-",
49 | User: "-",
50 | Time: time.Date(2011, 6, 25, 20, 0, 4, 0, time.UTC),
51 | Method: "GET",
52 | Path: "/loggen/loggen/loggen/loggen/loggen/loggen/loggen",
53 | Code: 200,
54 | Size: 650,
55 | Referer: "-",
56 | Agent: "golang/generator PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
57 | HttpXForwardedFor: "-",
58 | }
59 | }
60 |
61 | func (t TemplateData) WebServerDateTime() string {
62 | return t.Time.Format("02/Jan/2006:15:04:05 -0700")
63 | }
64 |
65 | func RandomData() TemplateData {
66 | rand.Seed(time.Now().UTC().UnixNano())
67 |
68 | c, _ := wr.NewChooser(
69 | wr.Choice{Item: 200, Weight: 7},
70 | wr.Choice{Item: 404, Weight: 3},
71 | wr.Choice{Item: 503, Weight: 1},
72 | wr.Choice{Item: 302, Weight: 2},
73 | wr.Choice{Item: 403, Weight: 2},
74 | )
75 |
76 | return TemplateData{
77 | Remote: randomdata.IpV4Address(),
78 | Host: "-",
79 | User: "-",
80 | Time: time.Now(),
81 | Method: randomdata.StringSample("GET", "POST", "PUT"),
82 | Path: randomdata.StringSample("/", "/blog", "/index.html", "/products"),
83 | Code: c.Pick().(int),
84 | Size: rand.Intn(25000-100) + 100,
85 | Referer: "-",
86 | Agent: randomdata.UserAgentString(),
87 | HttpXForwardedFor: "-",
88 | }
89 | }
90 |
91 | func (t TemplateData) Severity() string {
92 | return strconv.FormatInt(int64(t.Code), 10)
93 | }
94 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/kube-logging/log-generator
2 |
3 | go 1.23.6
4 |
5 | require (
6 | github.com/Pallinder/go-randomdata v1.2.0
7 | github.com/cenkalti/backoff/v4 v4.3.0
8 | github.com/dhoomakethu/stress v0.0.0-20230620054616-291ff04e1c89
9 | github.com/gin-gonic/gin v1.10.1
10 | github.com/go-viper/encoding/ini v0.1.1
11 | github.com/kube-logging/log-generator/formats/custom v0.0.0-20250206095042-0df4b7b9896b
12 | github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b
13 | github.com/lthibault/jitterbug v2.0.0+incompatible
14 | github.com/mroth/weightedrand v1.0.0
15 | github.com/prometheus/client_golang v1.22.0
16 | github.com/sirupsen/logrus v1.9.3
17 | github.com/spf13/viper v1.20.1
18 | )
19 |
20 | require (
21 | github.com/beorn7/perks v1.0.1 // indirect
22 | github.com/bytedance/sonic v1.12.8 // indirect
23 | github.com/bytedance/sonic/loader v0.2.3 // indirect
24 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
25 | github.com/cloudwego/base64x v0.1.5 // indirect
26 | github.com/fsnotify/fsnotify v1.8.0 // indirect
27 | github.com/gabriel-vasile/mimetype v1.4.8 // indirect
28 | github.com/gin-contrib/sse v1.0.0 // indirect
29 | github.com/go-ole/go-ole v1.3.0 // indirect
30 | github.com/go-playground/locales v0.14.1 // indirect
31 | github.com/go-playground/universal-translator v0.18.1 // indirect
32 | github.com/go-playground/validator/v10 v10.24.0 // indirect
33 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
34 | github.com/goccy/go-json v0.10.5 // indirect
35 | github.com/json-iterator/go v1.1.12 // indirect
36 | github.com/klauspost/cpuid/v2 v2.2.9 // indirect
37 | github.com/leodido/go-urn v1.4.0 // indirect
38 | github.com/mattn/go-isatty v0.0.20 // indirect
39 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
40 | github.com/modern-go/reflect2 v1.0.2 // indirect
41 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
42 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect
43 | github.com/prometheus/client_model v0.6.1 // indirect
44 | github.com/prometheus/common v0.62.0 // indirect
45 | github.com/prometheus/procfs v0.15.1 // indirect
46 | github.com/rogpeppe/go-internal v1.11.0 // indirect
47 | github.com/sagikazarmark/locafero v0.7.0 // indirect
48 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect
49 | github.com/sourcegraph/conc v0.3.0 // indirect
50 | github.com/spf13/afero v1.12.0 // indirect
51 | github.com/spf13/cast v1.7.1 // indirect
52 | github.com/spf13/pflag v1.0.6 // indirect
53 | github.com/subosito/gotenv v1.6.0 // indirect
54 | github.com/tklauser/go-sysconf v0.3.14 // indirect
55 | github.com/tklauser/numcpus v0.9.0 // indirect
56 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
57 | github.com/ugorji/go/codec v1.2.12 // indirect
58 | github.com/yusufpapurcu/wmi v1.2.4 // indirect
59 | go.uber.org/multierr v1.11.0 // indirect
60 | golang.org/x/arch v0.14.0 // indirect
61 | golang.org/x/crypto v0.36.0 // indirect
62 | golang.org/x/net v0.38.0 // indirect
63 | golang.org/x/sys v0.31.0 // indirect
64 | golang.org/x/text v0.23.0 // indirect
65 | google.golang.org/protobuf v1.36.5 // indirect
66 | gopkg.in/ini.v1 v1.67.0 // indirect
67 | gopkg.in/yaml.v3 v3.0.1 // indirect
68 | )
69 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2 | github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg=
3 | github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y=
4 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
5 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
7 | github.com/bytedance/sonic v1.12.8 h1:4xYRVRlXIgvSZ4e8iVTlMF5szgpXd4AfvuWgA8I8lgs=
8 | github.com/bytedance/sonic v1.12.8/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
9 | github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
10 | github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
11 | github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
12 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
13 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
14 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
15 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
16 | github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
17 | github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
18 | github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
19 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
20 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23 | github.com/dhoomakethu/stress v0.0.0-20230620054616-291ff04e1c89 h1:vZ773HzivjjoA7hutxZqT9Li69X+cxtaOaE3Zvnespo=
24 | github.com/dhoomakethu/stress v0.0.0-20230620054616-291ff04e1c89/go.mod h1:3kLGAoowVCZDjyDQRS04+u7uBMIzkQY8K3hvt4NTM9s=
25 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
26 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
27 | github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
28 | github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
29 | github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
30 | github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
31 | github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
32 | github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
33 | github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
34 | github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
35 | github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
36 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
37 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
38 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
39 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
40 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
41 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
42 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
43 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
44 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
45 | github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
46 | github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
47 | github.com/go-viper/encoding/ini v0.1.1 h1:MVWY7B2XNw7lnOqHutGRc97bF3rP7omOdgjdMPAJgbs=
48 | github.com/go-viper/encoding/ini v0.1.1/go.mod h1:Pfi4M2V1eAGJVZ5q6FrkHPhtHED2YgLlXhvgMVrB+YQ=
49 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
50 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
51 | github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
52 | github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
53 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
54 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
55 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
56 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
57 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
58 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
59 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
60 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
61 | github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
62 | github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
63 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
64 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
65 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
66 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
67 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
68 | github.com/kube-logging/log-generator/formats/custom v0.0.0-20250206095042-0df4b7b9896b h1:CE8weOgqCWItZULFbwQANDEZS59hJDcE6DHrEJX7b3I=
69 | github.com/kube-logging/log-generator/formats/custom v0.0.0-20250206095042-0df4b7b9896b/go.mod h1:tJhnbg95TNQwqQGkGLIixQuX20C29F1yqENREBY4BWI=
70 | github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b h1:qeGOor3k0POAnVkTlno/AXf71lefey7CS9SD03QIcfA=
71 | github.com/kube-logging/log-generator/log v0.0.0-20250206095042-0df4b7b9896b/go.mod h1:+ZQ22F6eQ1BAkfzKa85LS2XuKgqBEgVOnJVmlP97yls=
72 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
73 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
74 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
75 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
76 | github.com/lthibault/jitterbug v2.0.0+incompatible h1:qouq51IKzlMx25+15jbxhC/d79YyTj0q6XFoptNqaUw=
77 | github.com/lthibault/jitterbug v2.0.0+incompatible/go.mod h1:2l7akWd27PScEs6YkjyUVj/8hKgNhbbQ3KiJgJtlf6o=
78 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
79 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
80 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
81 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
82 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
83 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
84 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
85 | github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
86 | github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
87 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
88 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
89 | github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
90 | github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
91 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
92 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
93 | github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
94 | github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
95 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
96 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
97 | github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
98 | github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
99 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
100 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
101 | github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
102 | github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
103 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
104 | github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
105 | github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
106 | github.com/shirou/gopsutil v3.21.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
107 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
108 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
109 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
110 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
111 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
112 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
113 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
114 | github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
115 | github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
116 | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
117 | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
118 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
119 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
120 | github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
121 | github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
122 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
123 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
124 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
125 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
126 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
127 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
128 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
129 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
130 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
131 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
132 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
133 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
134 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
135 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
136 | github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
137 | github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
138 | github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
139 | github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
140 | github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
141 | github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
142 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
143 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
144 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
145 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
146 | github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
147 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
148 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
149 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
150 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
151 | golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
152 | golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
153 | golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
154 | golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
155 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
156 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
157 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
158 | golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
159 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
160 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
161 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
162 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
163 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
164 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
165 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
166 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
167 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
168 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
169 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
170 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
171 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
172 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
173 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
174 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
175 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
176 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
177 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
178 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
179 |
--------------------------------------------------------------------------------
/log/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: check
2 | check:
3 | go fmt
4 | go vet
5 |
6 | .PHONY: test
7 | test:
8 | go test ${GOFLAGS} ./...
9 |
--------------------------------------------------------------------------------
/log/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/kube-logging/log-generator/log
2 |
3 | go 1.23.6
4 |
5 | require (
6 | github.com/prometheus/client_golang v1.20.5
7 | github.com/sirupsen/logrus v1.9.3
8 | )
9 |
10 | require (
11 | github.com/beorn7/perks v1.0.1 // indirect
12 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
13 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
14 | github.com/prometheus/client_model v0.6.1 // indirect
15 | github.com/prometheus/common v0.62.0 // indirect
16 | github.com/prometheus/procfs v0.15.1 // indirect
17 | golang.org/x/sys v0.30.0 // indirect
18 | google.golang.org/protobuf v1.36.5 // indirect
19 | )
20 |
--------------------------------------------------------------------------------
/log/go.sum:
--------------------------------------------------------------------------------
1 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
9 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
10 | github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
11 | github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
12 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
13 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
14 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16 | github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
17 | github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
18 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
19 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
20 | github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
21 | github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
22 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
23 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
24 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
25 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
27 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
28 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
29 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
30 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
31 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
32 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
33 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
34 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
35 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
36 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
37 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
38 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
39 |
--------------------------------------------------------------------------------
/log/log.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package log
16 |
17 | import (
18 | "github.com/prometheus/client_golang/prometheus"
19 | )
20 |
21 | type Log interface {
22 | String() (string, float64)
23 | Labels() prometheus.Labels
24 | IsFramed() bool
25 | SetFramed(bool)
26 | }
27 |
--------------------------------------------------------------------------------
/log/template.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package log
16 |
17 | import (
18 | "fmt"
19 | "io/fs"
20 | "strings"
21 | "text/template"
22 |
23 | log "github.com/sirupsen/logrus"
24 |
25 | "github.com/prometheus/client_golang/prometheus"
26 | )
27 |
28 | type LogTemplateData interface {
29 | Severity() string
30 | }
31 |
32 | type LogTemplate struct {
33 | Format string
34 |
35 | template *template.Template
36 | data LogTemplateData
37 | isFramed bool
38 | }
39 |
40 | func NewLogTemplate(format string, fs fs.FS, data LogTemplateData) (*LogTemplate, error) {
41 | template, err := loadTemplate(format, fs)
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | return &LogTemplate{
47 | Format: format,
48 | template: template,
49 | data: data,
50 | }, nil
51 | }
52 |
53 | func FormatNames(fs fs.FS) []string {
54 | formats := []string{}
55 |
56 | for _, t := range LoadAllTemplates(fs) {
57 | formats = append(formats, strings.TrimSuffix(t.Name(), ".tmpl"))
58 | }
59 |
60 | return formats
61 | }
62 |
63 | func (l *LogTemplate) String() (string, float64) {
64 | var b strings.Builder
65 | if err := l.template.Execute(&b, l.data); err != nil {
66 | log.Panic(err.Error())
67 | }
68 |
69 | str := strings.TrimSuffix(b.String(), "\n")
70 |
71 | return str, float64(len([]byte(str)))
72 | }
73 |
74 | func (l *LogTemplate) IsFramed() bool {
75 | return l.isFramed
76 | }
77 |
78 | func (l *LogTemplate) SetFramed(f bool) {
79 | l.isFramed = f
80 | }
81 |
82 | func (l *LogTemplate) Labels() prometheus.Labels {
83 | return prometheus.Labels{
84 | "type": l.Format,
85 | "severity": l.data.Severity(),
86 | }
87 | }
88 |
89 | func loadTemplate(name string, fs fs.FS) (*template.Template, error) {
90 | // web.a.b.c => web.tmpl
91 | templateFileName, _, structuredFormatName := strings.Cut(name, ".")
92 | templateFileName += ".tmpl"
93 |
94 | template, err := template.ParseFS(fs, templateFileName)
95 | if err != nil {
96 | return nil, fmt.Errorf("could not parse format %q, %v", name, err)
97 | }
98 |
99 | if t := template.Lookup(name); t != nil {
100 | t.Option("missingkey=error")
101 | return t, nil
102 | }
103 |
104 | if t := template.Lookup(templateFileName); t != nil && !structuredFormatName {
105 | t.Option("missingkey=error")
106 | return t, nil
107 | }
108 |
109 | return nil, fmt.Errorf("could not find format %q", name)
110 | }
111 |
112 | func LoadAllTemplates(fs fs.FS) []*template.Template {
113 | return template.Must(template.ParseFS(fs, "*.tmpl")).Templates()
114 | }
115 |
--------------------------------------------------------------------------------
/loggen/loggen.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package loggen
16 |
17 | import (
18 | "bytes"
19 | "container/list"
20 | "encoding/json"
21 | "fmt"
22 | "net/http"
23 | "os"
24 | "os/signal"
25 | "sync"
26 | "time"
27 |
28 | "github.com/gin-gonic/gin"
29 | "github.com/lthibault/jitterbug"
30 | logger "github.com/sirupsen/logrus"
31 |
32 | "github.com/kube-logging/log-generator/conf"
33 | "github.com/kube-logging/log-generator/formats"
34 | "github.com/kube-logging/log-generator/formats/golang"
35 | "github.com/kube-logging/log-generator/formats/web"
36 | "github.com/kube-logging/log-generator/log"
37 | )
38 |
39 | type List struct {
40 | *list.List
41 | }
42 |
43 | type LogGen struct {
44 | EventPerSec int `json:"event_per_sec"`
45 | BytePerSec int `json:"byte_per_sec"`
46 | Randomise bool `json:"randomise"`
47 | ActiveRequests List `json:"active_requests"`
48 | GolangLog golang.GolangLogIntensity `json:"golang_log"`
49 |
50 | m sync.Mutex `json:"-"`
51 | writer LogWriter
52 | }
53 |
54 | type LogGenRequest struct {
55 | Type string `json:"type"`
56 | Format string `json:"format"`
57 | Count int `json:"count"`
58 | Framing bool `json:"framing"`
59 | }
60 |
61 | func New() *LogGen {
62 | return &LogGen{
63 | EventPerSec: conf.Viper.GetInt("message.event-per-sec"),
64 | BytePerSec: conf.Viper.GetInt("message.byte-per-sec"),
65 | Randomise: conf.Viper.GetBool("message.randomise"),
66 | ActiveRequests: List{list.New()},
67 | }
68 | }
69 |
70 | func (l *List) MarshalJSON() ([]byte, error) {
71 | b := bytes.NewBufferString("[")
72 |
73 | for e := l.Front(); e != nil; e = e.Next() {
74 | m, err := json.Marshal(e.Value)
75 |
76 | if err != nil {
77 | return nil, err
78 | }
79 |
80 | b.WriteString(string(m))
81 |
82 | if e.Next() != nil {
83 | b.WriteRune(',')
84 | }
85 | }
86 |
87 | b.WriteString("]")
88 | return b.Bytes(), nil
89 | }
90 |
91 | func (l *LogGen) FormatsGetHandler(ctx *gin.Context) {
92 | ctx.JSON(http.StatusOK, formats.FormatsByType())
93 | }
94 |
95 | func (l *LogGen) GetHandler(ctx *gin.Context) {
96 | l.m.Lock()
97 | defer l.m.Unlock()
98 |
99 | ctx.JSON(http.StatusOK, l)
100 | }
101 |
102 | func (l *LogGen) PostHandler(ctx *gin.Context) {
103 | var lr LogGenRequest
104 | if err := ctx.ShouldBindJSON(&lr); err != nil {
105 | logger.Error(err.Error())
106 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
107 | return
108 | }
109 |
110 | if err := lr.Validate(); err != nil {
111 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
112 | return
113 | }
114 |
115 | l.m.Lock()
116 | defer l.m.Unlock()
117 |
118 | l.ActiveRequests.PushBack(&lr)
119 |
120 | ctx.JSON(http.StatusOK, lr)
121 | }
122 |
123 | func (lr *LogGenRequest) Validate() error {
124 | if _, exists := formats.FormatsByType()[lr.Type]; !exists {
125 | return fmt.Errorf("type %q does not exist", lr.Type)
126 | }
127 |
128 | return nil
129 | }
130 |
131 | func (lr *LogGenRequest) process(lg *LogGen) log.Log {
132 | if lr.Count <= 0 {
133 | return nil
134 | }
135 |
136 | // TODO configuration management for custom formats?
137 | if lr.Type == "golang" {
138 | return formats.NewGolangRandom(lg.GolangLog)
139 | }
140 |
141 | msg, err := formats.LogFactory(lr.Type, lr.Format, lg.Randomise)
142 |
143 | if err != nil {
144 | logger.Warnf("Error generating log from request %v, %v", lr, err)
145 | return nil
146 | }
147 |
148 | lr.Count--
149 | return msg
150 | }
151 |
152 | func tickerForByte(bandwith int, j jitterbug.Jitter) *jitterbug.Ticker {
153 | l, _ := formats.NewWeb("nginx", web.TemplateFS)
154 | _, length := l.String()
155 | events := float64(1) / (float64(length) / float64(bandwith))
156 | duration := float64(1000) / float64(events)
157 | return jitterbug.New(time.Duration(duration)*time.Millisecond, j)
158 |
159 | }
160 |
161 | func tickerForEvent(events int, j jitterbug.Jitter) *jitterbug.Ticker {
162 | duration := float64(1000) / float64(events)
163 | return jitterbug.New(time.Duration(duration)*time.Millisecond, j)
164 | }
165 |
166 | func (l *LogGen) GolangGetHandler(c *gin.Context) {
167 | c.JSON(http.StatusOK, l.GolangLog)
168 | }
169 |
170 | func (l *LogGen) GolangPatchHandler(c *gin.Context) {
171 | if err := c.ShouldBindJSON(&l.GolangLog); err != nil {
172 | logger.Error(err.Error())
173 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
174 | return
175 | }
176 |
177 | l.golangSet()
178 | c.JSON(http.StatusOK, l.GolangLog)
179 | }
180 |
181 | func uintPtr(u uint) *uint {
182 | return &u
183 | }
184 |
185 | func (l *LogGen) golangSet() error {
186 | if l.GolangLog.ErrorWeight == nil {
187 | l.GolangLog.ErrorWeight = uintPtr(conf.Viper.GetUint("golang.weight.error"))
188 | }
189 | if l.GolangLog.WarningWeight == nil {
190 | l.GolangLog.WarningWeight = uintPtr(conf.Viper.GetUint("golang.weight.warning"))
191 | }
192 | if l.GolangLog.InfoWeight == nil {
193 | l.GolangLog.InfoWeight = uintPtr(conf.Viper.GetUint("golang.weight.info"))
194 | }
195 | if l.GolangLog.DebugWeight == nil {
196 | l.GolangLog.DebugWeight = uintPtr(conf.Viper.GetUint("golang.weight.debug"))
197 | }
198 |
199 | return nil
200 | }
201 |
202 | func (l *LogGen) processRequests() bool {
203 | l.m.Lock()
204 | logs := make([]log.Log, 0, l.ActiveRequests.Len())
205 |
206 | e := l.ActiveRequests.Front()
207 | for e != nil {
208 | request := e.Value.(*LogGenRequest)
209 |
210 | msg := request.process(l)
211 | if msg == nil {
212 | tmp := e
213 | e = e.Next()
214 | l.ActiveRequests.Remove(tmp)
215 | continue
216 | }
217 |
218 | if request.Framing {
219 | msg.SetFramed(true)
220 | }
221 |
222 | logs = append(logs, msg)
223 | e = e.Next()
224 | }
225 | l.m.Unlock()
226 |
227 | if len(logs) == 0 {
228 | return false
229 | }
230 |
231 | for _, msg := range logs {
232 | l.writer.Send(msg)
233 | }
234 |
235 | return true
236 | }
237 |
238 | func (l *LogGen) Run() {
239 | interrupt := make(chan os.Signal, 1)
240 | signal.Notify(interrupt, os.Interrupt)
241 | done := make(chan bool, 1)
242 |
243 | go func() {
244 |
245 | // TODO implement main loop for custom formats?
246 |
247 | var counter = 0
248 | var ticker *jitterbug.Ticker
249 |
250 | // jitter := &jitterbug.Norm{Stdev: time.Millisecond * 300}
251 | // TODO find a way to set Jitter from params
252 | jitter := &jitterbug.Norm{}
253 |
254 | if l.EventPerSec > 0 {
255 | ticker = tickerForEvent(l.EventPerSec, jitter)
256 | } else if l.BytePerSec > 0 {
257 | ticker = tickerForByte(l.BytePerSec, jitter)
258 | }
259 | count := conf.Viper.GetInt("message.count")
260 |
261 | if len(conf.Viper.GetString("destination.network")) != 0 {
262 | l.writer = newNetworkWriter(conf.Viper.GetString("destination.network"), conf.Viper.GetString("destination.address"))
263 | } else {
264 | l.writer = newStdoutWriter()
265 | }
266 |
267 | l.golangSet()
268 |
269 | for range ticker.C {
270 | if conf.Viper.GetBool("nginx.enabled") {
271 | l.sendIfCount(count, &counter, func() (log.Log, error) {
272 | if l.Randomise {
273 | return formats.NewRandomWeb("nginx", web.TemplateFS)
274 | } else {
275 | return formats.NewWeb("nginx", web.TemplateFS)
276 | }
277 | })
278 | }
279 | if conf.Viper.GetBool("apache.enabled") {
280 | l.sendIfCount(count, &counter, func() (log.Log, error) {
281 | if l.Randomise {
282 | return formats.NewRandomWeb("apache", web.TemplateFS)
283 | } else {
284 | return formats.NewWeb("apache", web.TemplateFS)
285 | }
286 | })
287 | }
288 | if conf.Viper.GetBool("golang.enabled") {
289 | l.sendIfCount(count, &counter, func() (log.Log, error) {
290 | return formats.NewGolangRandom(l.GolangLog), nil
291 | })
292 | }
293 | pendingRequests := l.processRequests()
294 |
295 | if !pendingRequests && count > 0 && !(counter < count) {
296 | done <- true
297 | break
298 | }
299 | }
300 |
301 | l.writer.Close()
302 | }()
303 |
304 | select {
305 | case <-interrupt:
306 | logger.Infoln("Recieved interrupt")
307 | break
308 | case <-done:
309 | break
310 | }
311 | }
312 |
313 | func (l *LogGen) sendIfCount(count int, counter *int, f func() (log.Log, error)) {
314 | if count == -1 || *counter < count {
315 | n, err := f()
316 | if err != nil {
317 | logger.Panic(err)
318 | }
319 | l.writer.Send(n)
320 | *counter++
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/loggen/writers.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package loggen
16 |
17 | import (
18 | "fmt"
19 | "net"
20 | "time"
21 |
22 | logger "github.com/sirupsen/logrus"
23 |
24 | "github.com/cenkalti/backoff/v4"
25 |
26 | "github.com/kube-logging/log-generator/log"
27 | "github.com/kube-logging/log-generator/metrics"
28 | )
29 |
30 | type LogWriter interface {
31 | Send(log.Log)
32 | Close()
33 | }
34 |
35 | type StdoutLogWriter struct{}
36 |
37 | func newStdoutWriter() LogWriter {
38 | return &StdoutLogWriter{}
39 | }
40 |
41 | func (*StdoutLogWriter) Send(l log.Log) {
42 | msg, size := l.String()
43 |
44 | if l.IsFramed() {
45 | msg = fmt.Sprintf("%d %s", len(msg), msg)
46 | }
47 |
48 | fmt.Println(msg)
49 |
50 | metrics.EventEmitted.With(l.Labels()).Inc()
51 | metrics.EventEmittedBytes.With(l.Labels()).Add(size)
52 | }
53 |
54 | func (*StdoutLogWriter) Close() {}
55 |
56 | type NetworkLogWriter struct {
57 | network string
58 | address string
59 | conn net.Conn
60 | }
61 |
62 | func newNetworkWriter(network string, address string) LogWriter {
63 | nlw := &NetworkLogWriter{
64 | network: network,
65 | address: address,
66 | }
67 |
68 | nlw.reconnect()
69 | return nlw
70 | }
71 |
72 | func (nlw *NetworkLogWriter) Send(l log.Log) {
73 | msg, size := l.String()
74 |
75 | if l.IsFramed() {
76 | msg = fmt.Sprintf("%d %s", len(msg), msg)
77 | } else {
78 | msg += "\n"
79 | }
80 |
81 | written := 0
82 | for {
83 | data := msg[written:]
84 |
85 | n, err := nlw.conn.Write([]byte(data))
86 | if err != nil {
87 | logger.Errorf("Error sending message (%q), reconnecting...", err.Error())
88 | nlw.reconnect()
89 | continue
90 | }
91 |
92 | written += n
93 |
94 | if written == len(msg) {
95 | break
96 | }
97 | }
98 |
99 | metrics.EventEmitted.With(l.Labels()).Inc()
100 | metrics.EventEmittedBytes.With(l.Labels()).Add(size)
101 | }
102 |
103 | func (nlw *NetworkLogWriter) Close() {
104 | if nlw.conn != nil {
105 | nlw.conn.Close()
106 | }
107 | }
108 |
109 | func (nlw *NetworkLogWriter) reconnect() {
110 | nlw.Close()
111 |
112 | bo := backoff.NewExponentialBackOff()
113 | bo.MaxElapsedTime = 0
114 |
115 | backoff.RetryNotify(func() error {
116 | logger.Infof("Connecting to %s %s...", nlw.network, nlw.address)
117 | var err error
118 | nlw.conn, err = net.DialTimeout(nlw.network, nlw.address, 5*time.Second)
119 | return err
120 | }, bo, func(err error, delay time.Duration) {
121 | logger.Errorf("Error connecting to server (%q), retrying in %s", err.Error(), delay.String())
122 | })
123 | }
124 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2021 Cisco Systems, Inc. and/or its affiliates
2 | // Copyright © 2023 Kube logging authors
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License."""
15 |
16 | package main
17 |
18 | import (
19 | "flag"
20 | "fmt"
21 | "net/http"
22 | "os"
23 | "time"
24 |
25 | "github.com/gin-gonic/gin"
26 | log "github.com/sirupsen/logrus"
27 |
28 | "github.com/kube-logging/log-generator/conf"
29 | "github.com/kube-logging/log-generator/loggen"
30 | "github.com/kube-logging/log-generator/metrics"
31 | "github.com/kube-logging/log-generator/stress"
32 | )
33 |
34 | func init() {
35 | log.SetOutput(os.Stdout)
36 | log.SetLevel(log.DebugLevel)
37 | conf.Init()
38 | }
39 |
40 | type LogLevel struct {
41 | Level string `json:"level"`
42 | LastModified time.Time `json:"last_modified"`
43 | }
44 |
45 | type State struct {
46 | Memory stress.Memory `json:"memory"`
47 | Cpu stress.CPU `json:"cpu"`
48 | LogLevel LogLevel `json:"log_level"`
49 | Loggen *loggen.LogGen `json:"loggen"`
50 | }
51 |
52 | func (s *State) logLevelGetHandler(c *gin.Context) {
53 | c.JSON(http.StatusOK, s.LogLevel)
54 | }
55 |
56 | func (s *State) logLevelSet() error {
57 | level, lErr := log.ParseLevel(s.LogLevel.Level)
58 | if lErr != nil {
59 | err := fmt.Errorf("%s valid logLeveles: panic fatal error warn warning info debug trace", lErr.Error())
60 | log.Error(err)
61 | return err
62 | }
63 | log.SetLevel(level)
64 | log.Infof("New loglevel: %s", level)
65 | s.LogLevel.LastModified = time.Now()
66 | return nil
67 | }
68 |
69 | func (s *State) logLevelPatchHandler(c *gin.Context) {
70 | if err := c.ShouldBindJSON(&s.LogLevel); err != nil {
71 | log.Error(err.Error())
72 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
73 | return
74 | }
75 | err := s.logLevelSet()
76 | if err != nil {
77 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
78 | return
79 |
80 | }
81 | c.JSON(http.StatusOK, s.LogLevel)
82 | }
83 |
84 | func (s *State) stateGetHandler(c *gin.Context) {
85 | c.JSON(http.StatusOK, s)
86 | }
87 |
88 | func (s *State) statePatchHandler(c *gin.Context) {
89 |
90 | var t State
91 | if err := c.ShouldBindJSON(&t); err != nil {
92 | log.Error(err.Error())
93 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
94 | return
95 | }
96 |
97 | if t.Memory != (stress.Memory{}) {
98 | s.Memory.CopyFrom(&t.Memory)
99 | s.Memory.Stress()
100 | }
101 |
102 | if t.Cpu != (stress.CPU{}) {
103 | s.Cpu = t.Cpu
104 | s.Cpu.Stress()
105 | }
106 |
107 | if t.LogLevel != (LogLevel{}) {
108 | s.LogLevel = t.LogLevel
109 | s.logLevelSet()
110 | }
111 | c.JSON(http.StatusOK, s)
112 | }
113 |
114 | func exceptionsGoCall(c *gin.Context) {
115 | log.Infoln("exceptionsGo")
116 | c.String(http.StatusOK, "exceptionsGo")
117 | }
118 |
119 | func main() {
120 | metrics.Startup = time.Now()
121 |
122 | apiAddr := conf.Viper.GetString("api.addr")
123 | apiBasePath := conf.Viper.GetString("api.basePath")
124 |
125 | flag.Parse()
126 |
127 | var s State
128 | s.Loggen = loggen.New()
129 | s.LogLevel.Level = log.GetLevel().String()
130 |
131 | go func() {
132 | log.Debugf("api listen on: %s, basePath: %s", apiAddr, apiBasePath)
133 | r := gin.New()
134 | api := r.Group(apiBasePath)
135 | api.GET("metrics", metrics.Handler())
136 | api.GET("/", s.stateGetHandler)
137 | api.PATCH("/", s.statePatchHandler)
138 | api.GET("/loggen", s.Loggen.GetHandler)
139 | api.POST("/loggen", s.Loggen.PostHandler)
140 | api.GET("/loggen/formats", s.Loggen.FormatsGetHandler)
141 | api.GET("/memory", s.Memory.GetHandler)
142 | api.PATCH("/memory", s.Memory.PatchHandler)
143 | api.GET("/cpu", s.Cpu.GetHandler)
144 | api.PATCH("/cpu", s.Cpu.PatchHandler)
145 | api.GET("/log_level", s.logLevelGetHandler)
146 | api.PATCH("/log_level", s.logLevelPatchHandler)
147 | api.GET("/golang", s.Loggen.GolangGetHandler)
148 | api.PATCH("/golang", s.Loggen.GolangPatchHandler)
149 | api.GET("exceptions/go", exceptionsGoCall)
150 | api.PATCH("exceptions/go", exceptionsGoCall)
151 |
152 | r.Run(apiAddr)
153 | s.Memory.Wait()
154 | }()
155 |
156 | s.Loggen.Run()
157 | }
158 |
--------------------------------------------------------------------------------
/metrics/metrics.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package metrics
16 |
17 | import (
18 | "time"
19 |
20 | "github.com/gin-gonic/gin"
21 | "github.com/prometheus/client_golang/prometheus"
22 | "github.com/prometheus/client_golang/prometheus/promauto"
23 | "github.com/prometheus/client_golang/prometheus/promhttp"
24 | )
25 |
26 | var Startup time.Time
27 |
28 | var (
29 | EventEmitted = promauto.NewCounterVec(prometheus.CounterOpts{
30 | Name: "loggen_events_total",
31 | Help: "The total number of events",
32 | },
33 | []string{"type", "severity"})
34 |
35 | EventEmittedBytes = promauto.NewCounterVec(prometheus.CounterOpts{
36 | Name: "loggen_event_bytes_total",
37 | Help: "The total bytes of events",
38 | },
39 | []string{"type", "severity"})
40 | GeneratedLoad = promauto.NewCounterVec(prometheus.CounterOpts{
41 | Name: "generated_load",
42 | Help: "Generated load",
43 | },
44 | []string{"type"})
45 |
46 | Uptime = promauto.NewCounterFunc(
47 | prometheus.CounterOpts{
48 | Name: "uptime_seconds",
49 | Help: "Generator uptime.",
50 | }, func() float64 {
51 | return time.Since(Startup).Seconds()
52 | },
53 | )
54 | )
55 |
56 | func Handler() gin.HandlerFunc {
57 | h := promhttp.Handler()
58 |
59 | return func(c *gin.Context) {
60 | h.ServeHTTP(c.Writer, c.Request)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/stress/cpu.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package stress
16 |
17 | import (
18 | "net/http"
19 | "time"
20 |
21 | "github.com/dhoomakethu/stress/utils"
22 | "github.com/gin-gonic/gin"
23 | log "github.com/sirupsen/logrus"
24 |
25 | "github.com/kube-logging/log-generator/metrics"
26 | )
27 |
28 | type CPU struct {
29 | Load float64 `json:"load"`
30 | Duration time.Duration `json:"duration"`
31 | Active time.Time `json:"active"`
32 | Core float64 `json:"core"`
33 | LastModified time.Time `json:"last_modified"`
34 | }
35 |
36 | func (c *CPU) GetHandler(ctx *gin.Context) {
37 | ctx.JSON(http.StatusOK, c)
38 | }
39 |
40 | func (c *CPU) PatchHandler(ctx *gin.Context) {
41 | if err := ctx.ShouldBindJSON(c); err != nil {
42 | log.Error(err.Error())
43 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
44 | return
45 | }
46 | err := c.Stress()
47 | if err != nil {
48 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
49 | return
50 |
51 | }
52 | ctx.JSON(http.StatusOK, c)
53 | }
54 |
55 | func (c *CPU) Stress() error {
56 | c.LastModified = time.Now()
57 | c.Active = time.Now().Add(c.Duration * time.Second)
58 | go c.cpuLoad()
59 | return nil
60 | }
61 |
62 | func (c CPU) cpuLoad() {
63 | log.Debugf("CPU load test started, duration: %s", (c.Duration * time.Second).String())
64 | sampleInterval := 100 * time.Millisecond
65 | controller := utils.NewCpuLoadController(sampleInterval, c.Load)
66 | monitor := utils.NewCpuLoadMonitor(c.Core, sampleInterval)
67 | actuator := utils.NewCpuLoadGenerator(controller, monitor, c.Duration)
68 | metrics.GeneratedLoad.WithLabelValues("cpu").Add(float64(c.Load))
69 | utils.RunCpuLoader(actuator)
70 | metrics.GeneratedLoad.DeleteLabelValues("cpu")
71 | log.Debugln("CPU load test done.")
72 | }
73 |
--------------------------------------------------------------------------------
/stress/memory.go:
--------------------------------------------------------------------------------
1 | // Copyright © 2023 Kube logging authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License."""
14 |
15 | package stress
16 |
17 | import (
18 | "net/http"
19 | "runtime"
20 | "sync"
21 | "time"
22 |
23 | "github.com/gin-gonic/gin"
24 | log "github.com/sirupsen/logrus"
25 |
26 | "github.com/kube-logging/log-generator/metrics"
27 | )
28 |
29 | type Memory struct {
30 | Megabyte int64 `json:"megabyte"`
31 | Active time.Time `json:"active"`
32 | Duration time.Duration `json:"duration"`
33 | LastModified time.Time `json:"last_modified"`
34 | mutex sync.Mutex `json:"-"`
35 | wg sync.WaitGroup `json:"-"`
36 | }
37 |
38 | func (m *Memory) CopyFrom(s *Memory) {
39 | m.Megabyte = s.Megabyte
40 | m.Active = s.Active
41 | m.Duration = s.Duration
42 | m.LastModified = s.LastModified
43 | }
44 |
45 | func (m *Memory) GetHandler(ctx *gin.Context) {
46 | ctx.JSON(http.StatusOK, m)
47 | }
48 |
49 | func (m *Memory) PatchHandler(ctx *gin.Context) {
50 | if err := ctx.ShouldBindJSON(m); err != nil {
51 | log.Error(err.Error())
52 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
53 | return
54 | }
55 | err := m.Stress()
56 | if err != nil {
57 | ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
58 | return
59 |
60 | }
61 | ctx.JSON(http.StatusOK, m)
62 | }
63 |
64 | func (m *Memory) Stress() error {
65 | m.LastModified = time.Now()
66 | m.Active = time.Now().Add(m.Duration * time.Second)
67 | go m.memoryBallast()
68 | return nil
69 | }
70 |
71 | func (m *Memory) Wait() {
72 | m.wg.Wait()
73 | }
74 |
75 | func (m *Memory) memoryBallast() {
76 | m.wg.Add(1)
77 | defer m.wg.Done()
78 | m.mutex.Lock()
79 | defer m.mutex.Unlock()
80 |
81 | log.Debugf("MEM load test started. - %s", time.Now().String())
82 | ballast := make([]byte, m.Megabyte<<20)
83 | metrics.GeneratedLoad.WithLabelValues("memory").Add(float64(m.Megabyte))
84 | for i := 0; i < len(ballast); i++ {
85 | ballast[i] = byte('A')
86 | }
87 | <-time.After(m.Duration * time.Second)
88 | ballast = nil
89 | runtime.GC()
90 | metrics.GeneratedLoad.DeleteLabelValues("memory")
91 | log.Debugf("MEM load test done.- %s", time.Now().String())
92 | }
93 |
--------------------------------------------------------------------------------