├── .chglog
├── CHANGELOG.tpl.md
├── RELNOTES.tmpl
└── config.yml
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ ├── feature_request.yaml
│ └── submit_question.yaml
└── workflows
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── config
├── share
├── status.compress.html
└── status.template.html
├── src
├── ngx_http_vhost_traffic_status_control.c
├── ngx_http_vhost_traffic_status_control.h
├── ngx_http_vhost_traffic_status_display.c
├── ngx_http_vhost_traffic_status_display.h
├── ngx_http_vhost_traffic_status_display_json.c
├── ngx_http_vhost_traffic_status_display_json.h
├── ngx_http_vhost_traffic_status_display_prometheus.c
├── ngx_http_vhost_traffic_status_display_prometheus.h
├── ngx_http_vhost_traffic_status_dump.c
├── ngx_http_vhost_traffic_status_dump.h
├── ngx_http_vhost_traffic_status_filter.c
├── ngx_http_vhost_traffic_status_filter.h
├── ngx_http_vhost_traffic_status_limit.c
├── ngx_http_vhost_traffic_status_limit.h
├── ngx_http_vhost_traffic_status_module.c
├── ngx_http_vhost_traffic_status_module.h
├── ngx_http_vhost_traffic_status_module_html.h
├── ngx_http_vhost_traffic_status_node.c
├── ngx_http_vhost_traffic_status_node.h
├── ngx_http_vhost_traffic_status_set.c
├── ngx_http_vhost_traffic_status_set.h
├── ngx_http_vhost_traffic_status_shm.c
├── ngx_http_vhost_traffic_status_shm.h
├── ngx_http_vhost_traffic_status_string.c
├── ngx_http_vhost_traffic_status_string.h
├── ngx_http_vhost_traffic_status_variables.c
└── ngx_http_vhost_traffic_status_variables.h
├── t
├── 000.display_html.t
├── 001.display_json.t
├── 002.check_json_syntax.t
├── 003.filter_by_host.t
├── 004.filter_by_set_key.t
├── 005.filter_check_duplicate.t
├── 006.control_status_fully.t
├── 007.control_status_group.t
├── 008.control_status_zone.t
├── 009.control_reset_fully.t
├── 010.control_reset_group.t
├── 011.control_reset_zone.t
├── 012.control_delete_fully.t
├── 013.control_delete_group.t
├── 014.control_delete_zone.t
├── 015.vts_variables_by_lua.t
├── 016.limit_traffic_by_lua.t
├── 017.limit_traffic.t
├── 018.limit_traffic_by_set_key.t
├── 019.limit_traffic_check_duplicate.t
├── 020.display_sum_key.t
├── 021.set_by_filter.t
├── 022.display_prometheus.t
├── 023.histogram_buckets.t
└── 024.upstream_check.t
└── util
├── fileToHex.pl
├── tplToBuffer.sh
└── tplToDefine.sh
/.chglog/CHANGELOG.tpl.md:
--------------------------------------------------------------------------------
1 | {{ if .Versions -}}
2 |
3 | ## [Unreleased]
4 |
5 | {{ if .Unreleased.CommitGroups -}}
6 | {{ range .Unreleased.CommitGroups -}}
7 | ### {{ .Title }}
8 | {{ range .Commits -}}
9 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
10 | {{ end }}
11 | {{ end -}}
12 | {{ end -}}
13 | {{ end -}}
14 |
15 | {{ range .Versions }}
16 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
17 | {{ range .CommitGroups -}}
18 | ### {{ .Title }}
19 | {{ range .Commits -}}
20 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
21 | {{ end }}
22 | {{ end -}}
23 |
24 | {{- if .NoteGroups -}}
25 | {{ range .NoteGroups -}}
26 | ### {{ .Title }}
27 | {{ range .Notes }}
28 | {{ .Body }}
29 | {{ end }}
30 | {{ end -}}
31 | {{ end -}}
32 | {{ end -}}
33 |
34 | {{- if .Versions }}
35 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
36 | {{ range .Versions -}}
37 | {{ if .Tag.Previous -}}
38 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
39 | {{ end -}}
40 | {{ end -}}
41 | {{ end -}}
42 |
--------------------------------------------------------------------------------
/.chglog/RELNOTES.tmpl:
--------------------------------------------------------------------------------
1 | {{ range .Versions -}}
2 | Release {{ .Tag.Name}}
3 |
4 | Release {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
5 | {{ range .CommitGroups -}}
6 | ** {{ .Title }}
7 | {{ range .Commits -}}
8 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
9 | {{ end }}
10 | {{ end -}}
11 |
12 | {{- if .NoteGroups -}}
13 | {{ range .NoteGroups -}}
14 | ** {{ .Title }}
15 | {{ range .Notes }}
16 | {{ .Body }}
17 | {{ end }}
18 | {{ end -}}
19 | {{ end -}}
20 | {{ end -}}
21 |
--------------------------------------------------------------------------------
/.chglog/config.yml:
--------------------------------------------------------------------------------
1 | style: github
2 | template: CHANGELOG.tpl.md
3 | info:
4 | title: CHANGELOG
5 | repository_url: https://github.com/vozlt/nginx-module-vts
6 | options:
7 | commits:
8 | # filters:
9 | # Type:
10 | # - feat
11 | # - fix
12 | # - perf
13 | # - refactor
14 | commit_groups:
15 | # title_maps:
16 | # feat: Features
17 | # fix: Bug Fixes
18 | # perf: Performance Improvements
19 | # refactor: Code Refactoring
20 | header:
21 | pattern: "^(\\w*)\\:\\s(.*)$"
22 | pattern_maps:
23 | - Type
24 | - Subject
25 | notes:
26 | keywords:
27 | - BREAKING CHANGE
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Report incorrect behavior in this module
3 | title: "BUG: "
4 | labels: [bug]
5 |
6 | body:
7 | - type: checkboxes
8 | id: checks
9 | attributes:
10 | label: module version checks
11 | options:
12 | - label: >
13 | I have checked that this issue has not already been reported.
14 | required: true
15 | - type: textarea
16 | id: problem
17 | attributes:
18 | label: Issue Description
19 | description: >
20 | Please provide a description of the issue shown in the reproducible example.
21 | validations:
22 | required: true
23 | - type: textarea
24 | id: expected-behavior
25 | attributes:
26 | label: Expected Behavior
27 | description: >
28 | Please describe or show a code example of the expected behavior.
29 | validations:
30 | required: true
31 | - type: textarea
32 | id: version
33 | attributes:
34 | label: Installed Versions
35 | placeholder: >
36 | % sudo /usr/local/nginx/sbin/nginx -V
37 | nginx version: nginx/1.27.0
38 | built by gcc 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
39 | configure arguments: --add-module=../nginx-module-vts
40 | description: >
41 | Please paste the output of ``nginx -V``
42 | value: >
43 |
44 |
45 |
46 | Replace this line with the output of nginx -V
47 |
48 |
49 |
50 | validations:
51 | required: true
52 | - type: textarea
53 | id: conf
54 | attributes:
55 | label: Reproducible Example nginx.conf
56 | description: >
57 | Please paste the reproducible nginx.conf
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Suggest an idea for this module
3 | title: "ENH: "
4 | labels: [enhancement]
5 |
6 | body:
7 | - type: checkboxes
8 | id: checks
9 | attributes:
10 | label: Feature Type
11 | description: Please check what type of feature request you would like to propose.
12 | options:
13 | - label: >
14 | Adding new functionality to this module
15 | - label: >
16 | Changing existing functionality in this module
17 | - label: >
18 | Removing existing functionality in this module
19 | - type: textarea
20 | id: description
21 | attributes:
22 | label: Problem Description
23 | description: >
24 | Please describe what problem the feature would solve, e.g. "I wish I could use this module to ..."
25 | placeholder: >
26 | I wish I could use this module...
27 | validations:
28 | required: true
29 | - type: textarea
30 | id: feature
31 | attributes:
32 | label: Feature Description
33 | description: >
34 | Please describe how the new feature would be implemented, using psudocode if relevant.
35 | validations:
36 | required: true
37 | - type: textarea
38 | id: context
39 | attributes:
40 | label: Additional Context
41 | description: >
42 | Please provide any relevant GitHub issues, code examples or references that help describe and support the feature request.
43 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/submit_question.yaml:
--------------------------------------------------------------------------------
1 | name: Submit Question
2 | description: Ask a general question about this module
3 | title: "QST: "
4 | labels: [question]
5 |
6 | body:
7 | - type: textarea
8 | id: question
9 | attributes:
10 | label: Question about this module
11 | - type: textarea
12 | id: version
13 | attributes:
14 | label: Installed Versions
15 | placeholder: >
16 | % sudo /usr/local/nginx/sbin/nginx -V
17 | nginx version: nginx/1.27.0
18 | built by gcc 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
19 | configure arguments: --add-module=../nginx-module-vts
20 | description: >
21 | Please paste the output of ``nginx -V``
22 | value: >
23 |
24 |
25 |
26 | Replace this line with the output of nginx -V
27 |
28 |
29 |
30 | - type: textarea
31 | id: conf
32 | attributes:
33 | label: Reproducible Example nginx.conf
34 | description: >
35 | Please paste the reproducible nginx.conf
36 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | test:
11 | name: 'build'
12 | runs-on: ubuntu-24.04
13 | steps:
14 | - name: 'checkout'
15 | uses: actions/checkout@v3
16 | with:
17 | path: nginx-module-vts
18 | - name: 'checkout nginx'
19 | uses: actions/checkout@v3
20 | with:
21 | repository: nginx/nginx
22 | path: nginx
23 | - name: 'checkout freenginx'
24 | uses: actions/checkout@v3
25 | with:
26 | repository: freenginx/nginx
27 | path: freenginx
28 | - name: 'checkout luajit2'
29 | uses: actions/checkout@v3
30 | with:
31 | repository: openresty/luajit2
32 | path: luajit2
33 | - name: 'checkout ngx_devel_kit'
34 | uses: actions/checkout@v3
35 | with:
36 | repository: vision5/ngx_devel_kit
37 | path: ngx_devel_kit
38 | - name: 'checkout lua-nginx-module'
39 | uses: actions/checkout@v3
40 | with:
41 | repository: openresty/lua-nginx-module
42 | path: lua-nginx-module
43 | - name: 'checkout lua-resty-core'
44 | uses: actions/checkout@v3
45 | with:
46 | repository: openresty/lua-resty-core
47 | path: lua-resty-core
48 | - name: 'checkout lua-resty-lrucache'
49 | uses: actions/checkout@v3
50 | with:
51 | repository: openresty/lua-resty-lrucache
52 | path: lua-resty-lrucache
53 | - name: 'build luajit2'
54 | working-directory: luajit2
55 | run: |
56 | make
57 | sudo make install
58 | sudo mkdir /usr/local/share/lua/5.1/resty
59 | - name: 'link resty lib'
60 | working-directory: /usr/local/share/lua/5.1/resty
61 | run: |
62 | sudo ln -s /home/runner/work/nginx-module-vts/nginx-module-vts/lua-resty-core/lib/resty/core core
63 | sudo ln -s /home/runner/work/nginx-module-vts/nginx-module-vts/lua-resty-core/lib/resty/core.lua core.lua
64 | sudo ln -s /home/runner/work/nginx-module-vts/nginx-module-vts/lua-resty-lrucache/lib/resty/lrucache lrucache
65 | sudo ln -s /home/runner/work/nginx-module-vts/nginx-module-vts/lua-resty-lrucache/lib/resty/lrucache.lua lrucache.lua
66 | - name: 'prepare nginx_upstream_check'
67 | uses: actions/checkout@v3
68 | with:
69 | repository: yaoweibin/nginx_upstream_check_module
70 | path: nginx_upstream_check
71 |
72 | - name: 'patch upstream_check'
73 | working-directory: nginx
74 | run: |
75 | patch -p1 < /home/runner/work/nginx-module-vts/nginx-module-vts/nginx_upstream_check/check_1.20.1+.patch
76 | - name: 'patch upstream_check for freenginx'
77 | working-directory: freenginx
78 | run: |
79 | patch -p1 < /home/runner/work/nginx-module-vts/nginx-module-vts/nginx_upstream_check/check_1.20.1+.patch
80 | - name: 'build nginx'
81 | working-directory: nginx
82 | run: |
83 | ./auto/configure --with-ld-opt="-Wl,-rpath,/usr/local/lib" --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/ngx_devel_kit --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/lua-nginx-module --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/nginx-module-vts --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/nginx_upstream_check
84 | make
85 | sudo make install
86 | /usr/local/nginx/sbin/nginx -V
87 | env:
88 | LUAJIT_LIB: /usr/local/lib
89 | LUAJIT_INC: /usr/local/include/luajit-2.1
90 | - name: 'build freenginx'
91 | working-directory: freenginx
92 | run: |
93 | ./auto/configure --prefix=/usr/local/freenginx --with-ld-opt="-Wl,-rpath,/usr/local/lib" --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/ngx_devel_kit --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/lua-nginx-module --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/nginx-module-vts --add-module=/home/runner/work/nginx-module-vts/nginx-module-vts/nginx_upstream_check
94 | make
95 | sudo make install
96 | /usr/local/freenginx/sbin/nginx -V
97 | env:
98 | LUAJIT_LIB: /usr/local/lib
99 | LUAJIT_INC: /usr/local/include/luajit-2.1
100 | - name: 'prepare cpanm'
101 | run: |
102 | sudo apt install -y cpanminus
103 | sudo cpanm --notest Test::Nginx::Socket > build.log 2>&1 || (cat build.log && exit 1)
104 | - name: 'prepare promtool'
105 | run: |
106 | sudo apt-get update && sudo apt-get install -y curl
107 | curl -L $(curl -s https://api.github.com/repos/prometheus/prometheus/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4) -o prometheus-latest.tar.gz
108 | tar xvf prometheus-latest.tar.gz
109 | sudo mv prometheus-*/promtool /usr/local/bin
110 | - name: 'test'
111 | working-directory: nginx-module-vts
112 | run: |
113 | echo "/usr/local/nginx/sbin/" >> $GITHUB_PATH
114 | sudo PATH=/usr/local/nginx/sbin:$PATH prove -r t
115 | - name: 'test upstream check'
116 | working-directory: nginx-module-vts
117 | run: |
118 | echo "/usr/local/nginx/sbin/" >> $GITHUB_PATH
119 | sudo TEST_UPSTREAM_CHECK=1 TEST_NGINX_SLEEP=1 PATH=/usr/local/nginx/sbin:$PATH prove t/024.upstream_check.t
120 | - name: 'test freenginx'
121 | working-directory: nginx-module-vts
122 | run: |
123 | echo "/usr/local/freenginx/sbin/" >> $GITHUB_PATH
124 | sudo PATH=/usr/local/freenginx/sbin:$PATH prove -r t
125 | - name: 'test upstream check for freenginx'
126 | working-directory: nginx-module-vts
127 | run: |
128 | echo "/usr/local/freenginx/sbin/" >> $GITHUB_PATH
129 | sudo TEST_UPSTREAM_CHECK=1 TEST_NGINX_SLEEP=1 PATH=/usr/local/freenginx/sbin:$PATH prove t/024.upstream_check.t
130 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | t/servroot
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | ## [Unreleased]
3 |
4 |
5 | ## [v0.2.4] - 2025-03-12
6 | ### Fix
7 | - escape uri in module side
8 |
9 |
10 | ## [v0.2.3] - 2025-01-01
11 | ### Ci
12 | - support freenginx
13 |
14 | ### Docs
15 | - Fix README
16 |
17 |
18 | ## [v0.2.2] - 2023-05-26
19 | ### Bugfix
20 | - fixed issues/228 Change the reffered source of upstream_states in shm_add_upstream()
21 | - fixed issues/248 Shared memory (lock|unlock) is set when using the ngx_http_vhost_traffic_status_display_get_size() function
22 |
23 | ### Bugfix
24 | - Add shmtx unlock
25 |
26 | ### Chore
27 | - add cpanm --notest in CI
28 |
29 | ### Test
30 | - Fix upstream check test properly
31 | - Add upstream check test
32 |
33 |
34 | ## [v0.2.1] - 2022-09-17
35 | ### Bugfix
36 | - use trimmed serverZones name
37 | - improved the accuracy of total(*) statistics by nginx-module-sts/pull/10
38 |
39 | ### Chore
40 | - Add CI badge in README ([#245](https://github.com/vozlt/nginx-module-vts/issues/245))
41 |
42 | ### Compatibility
43 | - fixed an issues/232 with compile errors in gcc 11.3
44 |
45 | ### Debug
46 | - added ngx_log_error() when ngx_http_vhost_traffic_status_node_position_key() failed for issues/212
47 |
48 | ### Docs
49 | - Fixed README
50 |
51 | ### Test
52 | - build without -Wno-stringop-overread ([#243](https://github.com/vozlt/nginx-module-vts/issues/243))
53 | - Add test for prometheus syntax
54 | - Add test for display prometheus
55 |
56 |
57 | ## [v0.2.0] - 2022-09-06
58 | ### Bugfix
59 | - fixed for PR[#238](https://github.com/vozlt/nginx-module-vts/issues/238)
60 | - fixed for PR[#238](https://github.com/vozlt/nginx-module-vts/issues/238)
61 | - fixed issues/204 that syntax error has occured
62 | - rollback to 549cc4d
63 | - fixed issues/137, issues/98 that maxSize in cacheZones is displayed incorrectly
64 | - fixed issues/174 that XSS vulnerability in the html page Feature: added moduleVersion field in format/json
65 | - added escape strings for filter names in JSON
66 | - fixed the sum value of histogram in upstream metrics
67 | - fixed to display all A records of server without zone directive in the upstream block.
68 |
69 | ### Chore
70 | - Change module version. ([#241](https://github.com/vozlt/nginx-module-vts/issues/241))
71 | - Use git-chglog
72 |
73 | ### Comment
74 | - added moduleVersion
75 | - added additional information about cacheZones
76 | - added tested versions
77 | - added a diagram for the order of module directives
78 |
79 | ### Compatibility
80 | - fixed ngx_http_vhost_traffic_status_display_get_upstream_nelts() to calculate all A records of server.
81 |
82 | ### Docs
83 | - Fix README
84 |
85 | ### Docs
86 | - fix simple typo, destory -> destroy
87 |
88 | ### Fix
89 | - limit the r->uri search scope to avoid overflow
90 |
91 | ### Prometheus
92 | - fix nginx_vts_filter_requests_total labels
93 | - remove request "total" metrics
94 |
95 | ### Refactor
96 | - changed version
97 | - changed spacing
98 | - changed spacing
99 | - changed if statement from merged pull/145
100 |
101 | ### Test
102 | - describe how to test and fix failed test case
103 |
104 |
105 | ## [v0.1.18] - 2018-06-22
106 | ### Bugfix
107 | - fixed issues/130 that nginx_vts_main_connections metrics mixed
108 | - fixed for issues/129 that worker process 4589 exited on signal 11
109 |
110 | ### Tag
111 | - v0.1.18
112 |
113 |
114 | ## [v0.1.17] - 2018-06-20
115 | ### Comment
116 | - added overCounts object explanation
117 | - added additional explanation of vhost_traffic_status_zone
118 |
119 | ### Compatibility
120 | - added "#if (NGX_HTTP_CACHE)" for the issues/122
121 |
122 | ### Delete
123 | - a.diff
124 |
125 | ### Feature
126 | - added TiB unit in format/html for the issues/111
127 | - added vhost_traffic_status_filter_max_node directive to limit the size of filters
128 | - added the histogram type of request processing time in format/json
129 | - added vhost_traffic_status_histogram_buckets directive to set the histogram type of request processing time in format/prometheus
130 | - added support for implementing format/prometheus
131 | - added request_time_counter, response_time_counter section to support accumulated request processing time for pull/67, issues/73
132 |
133 | ### Tag
134 | - v0.1.17
135 |
136 |
137 | ## [v0.1.16] - 2018-05-21
138 | ### Compatibility
139 | - fixed ngx_current_msec that changed in nginx-1.13.10 for the issues/121
140 |
141 | ### Fix
142 | - nginx will crash at vts module when configure file has no http block
143 | - nginx will crash at vts module when configure file has no http block
144 |
145 | ### Tag
146 | - v0.1.16
147 |
148 |
149 | ## [v0.1.15] - 2017-06-20
150 | ### Bugfix
151 | - fixed issues/79 that does not exited at "worker process is shutting down"
152 | - fixed issues/79 that does not exited at "worker process is shutting down"
153 |
154 | ### Comment
155 | - fixed to be compatible with version 0.27-gfm
156 |
157 | ### Compatibility
158 | - fixed goto label location for the issues/77
159 | - fixed some issues for the nginx-module-sts/issues/1
160 | - fixed "#define" macro to char array for the nginx-module-sts/issues/1
161 |
162 | ### Feature
163 | - changed ngx_http_vhost_traffic_status_node_time_queue_merge()
164 | - added vhost_traffic_status_dump to maintain statistics data permanently
165 | - added period parameter in vhost_traffic_status_average_method directive to change the average value after the elapse of time
166 |
167 | ### Fix
168 | - it is actually aam
169 |
170 | ### Tag
171 | - v0.1.15
172 |
173 |
174 | ## [v0.1.14] - 2017-03-21
175 | ### Comment
176 | - added the use cases & fixed vhost_traffic_status_bypass_(limit|stats) usage
177 |
178 | ### Compatibility
179 | - added segfault prevent routine for the issues/75
180 |
181 | ### Feature
182 | - added shared memory section to support shared memory information
183 | - added vhost_traffic_status_average_method to support for selecting an average formula
184 | - added sharedZones in JSON to support shared memory information
185 |
186 |
187 | ## [v0.1.13] - 2017-03-07
188 | ### Bugfix
189 | - fixed issues/(71|72) worker process exited on signal 11
190 |
191 | ### Comment
192 | - added nginx-vts-exporter & nginx-module-sysguard
193 | - added stream status modules
194 | - added modules nginx-module-sts and nginx-module-stream-sts
195 |
196 | ### Compatibility
197 | - added "#if (NGX_HTTP_CACHE)"
198 |
199 | ### Feature
200 | - added vhost_traffic_status_set_by_filter to support stats values access Feature: added "::main" in control to get only default status values
201 | - added vhost_traffic_status_display_sum_key for issues/61
202 | - added vhost_traffic_status_display_sum_key for issues/61
203 |
204 | ### Refactor
205 | - javascript tidy
206 |
207 |
208 | ## [v0.1.12] - 2017-02-08
209 | ### Feature
210 | - added hostname section for issues/37
211 | - added request_time section for issues/(43|57)
212 | - added request_time section for issues/(43|57)
213 | - added request_time section for issues/(43|57)
214 |
215 | ### Refactor
216 | - divided the source code
217 |
218 |
219 | ## [v0.1.11] - 2016-11-09
220 | ### Bugfix
221 | - fixed issues/56 that worker process exited on signal 11 if running control query without group argument or nonexistent group
222 | - fixed issues/52 that worker process exited on signal 11
223 | - fixed issues/6 that occured error(handler::shm_add_upstream() failed) when using fastcgi_pass $variables
224 | - fixed issues/45 that occurred segfault when balancer_by_lua breaks
225 |
226 | ### Compatibility
227 | - changed for issues/49 that occured errors when using compile with clang -Werror,-Wtautological-pointer-compare in osx os.
228 | - changed for issues/47 that occured errors when using compile with -Werror(Make all warnings into errors). The number returned by ngx_http_vhost_traffic_status_max_integer() consist of string without the suffix ULL(unsigned long long int).
229 |
230 | ### Tag
231 | - v0.1.11
232 | - v0.1.10
233 |
234 |
235 | ## [v0.1.10] - 2016-03-24
236 | ### Bugfix
237 | - initialize a variable(filter->filter_name.flushes) for issues/35 that worker process exited on signal 11
238 |
239 | ### Compatibility
240 | - added dynamic module build option for --add-dynamic-module in nginx 1.9.11
241 |
242 |
243 | ## [v0.1.9] - 2016-03-01
244 | ### Bugfix
245 | - initialize a variable(filter->filter_name.value.len) for issues/33 that occurred segfault when running "nginx -s reload"
246 |
247 | ### Exception
248 | - return NGX_CONF_ERROR if failed ngx_http_vhost_traffic_status_filter_unique()
249 |
250 | ### Feature
251 | - added vhost_traffic_status_display_jsonp to support JSONP
252 | - added vhost_traffic_status_display_jsonp to support JSONP
253 |
254 | ### Refactor
255 | - changed function names from ngx_vhost_* to ngx_http_vhost_*
256 |
257 |
258 | ## [v0.1.8] - 2015-12-15
259 | ### Feature
260 | - added support for implementing the feature that upstream peers use shared memory.(upstream zone directive)
261 |
262 |
263 | ## [v0.1.7] - 2015-12-11
264 | ### Bugfix
265 | - fixed issues/28 that can't use control functionality if location has more than a segment
266 |
267 | ### Comment
268 | - fixed spelling
269 |
270 | ### Compatibility
271 | - changed for issues/27 that error occurred(comparison of integers of different signs)
272 |
273 | ### Feature
274 | - added support for implementing traffic limit.
275 |
276 |
277 | ## [v0.1.6] - 2015-11-25
278 | ### Feature
279 | - added support for implementing variables for current traffic status values. It is starting with a $vts_*.
280 |
281 |
282 | ## [v0.1.5] - 2015-11-23
283 | ### Bugfix
284 | - fixed to work escape_json in ngx_http_vhost_traffic_status_display_set_filter_node()
285 |
286 | ### Compatibility
287 | - changed for issues/27 that ngx_vhost_traffic_status_group_to_string() macro is an error when using -Wstring-plus-int at clang compiler.
288 |
289 |
290 | ## [v0.1.4] - 2015-11-04
291 | ### Comment
292 | - fixed spelling
293 | - fixed spelling
294 | - fixed spelling
295 |
296 | ### Compatibility
297 | - fixed unused variables
298 |
299 | ### Feature
300 | - added vhost_traffic_status_filter to globally enable or disable the filter features. Feature: fixed vhost_traffic_status_filter_by_host to globally enable or disable. Feature: fixed vhost_traffic_status_filter_by_set_key to calculate user defined individual stats. Basically, country flags image is built-in in HTML. Feature: added vhost_traffic_status_filter_check_duplicate for deduplication of vhost_traffic_status_filter_by_set_key. Feature: added update interval in HTML.
301 |
302 |
303 | ## [v0.1.3] - 2015-10-21
304 | ### Bugfix
305 | - stats for cached responses with error_page directive do not create a cache file
306 |
307 | ### Feature
308 | - added vhost_traffic_status_filter_by_host, vhost_traffic_status_filter_by_set_key directive to set the dynamically keys
309 |
310 | ### Tag
311 | - v0.1.2
312 |
313 |
314 | ## [v0.1.2] - 2015-09-03
315 | ### Bugfix
316 | - added cache variable's lock routine in ngx_http_vhost_traffic_status_shm_add_cache() for issues/19
317 |
318 | ### Comment
319 | - added donation button
320 | - added uptime calculation
321 | - added the customizing
322 | - added the customizing
323 | - added the caveats
324 |
325 | ### Compatibility
326 | - added overflow handling routines of variables. It deals with the overflow of both 32bit and 64bit variables but I think that not be useful in 64bit variable(Max:16EB) at this moment.
327 |
328 |
329 | ## [v0.1.1] - 2015-05-28
330 | ### Feature
331 | - cache status support when using the proxy_cache directive
332 |
333 |
334 | ## v0.1.0 - 2015-05-28
335 | ### Bugfix
336 | - added the uscf found routine in ngx_http_vhost_traffic_status_shm_add_upstream() for issues/6
337 | - added default server_name "_" in ngx_http_vhost_traffic_status_shm_add_server(), if the server_name directive is not defined
338 | - added ngx_escape_json() in ngx_http_vhost_traffic_status_display_set_server() for the regular expressions names of server_name directive
339 | - added compare upstream hash. It does not updated upstream peers status so I have fixed it.
340 | - removed a reference(*shm_zone) in ngx_http_vhost_traffic_status_ctx_t.
341 | - changed the obtaining ms of phase for the keeping reference.
342 | - changed a reference from vtsn->stat_upstream.rtms to vtscf->vtsn_upstream->stat_upstream.rtms. It is referred to as non-existent reference after kept a reference.
343 |
344 | ### Comment
345 | - added the table of contents
346 |
347 | ### Compatibility
348 | - added response_time for the nginx v1.9.1(http://hg.nginx.org/nginx/rev/59fc60585f1e)
349 | - changed the position of nginx.h to avoid compile error on windows at v1.7.12
350 | - added ngx_http_vhost_traffic_status_escape_json() for less than 1.7.9
351 |
352 | ### Refactor
353 | - changed NGX_CONF_UNSET to 0 for uint32_t
354 | - changed uptime output from issue(pull/4#issuecomment-77839027)
355 | - added ngx_log_error() in ngx_http_vhost_traffic_status_handler()
356 | - changed length of key
357 | - changed from (ngx_atomic_t) to (ngx_atomic_uint_t) in the ngx_vhost_traffic_status_node_init() and ngx_vhost_traffic_status_node_set() for compile compatibility
358 | - added type casting(ngx_atomic_t) in the ngx_vhost_traffic_status_node_init() and ngx_vhost_traffic_status_node_set()
359 |
360 |
361 | [Unreleased]: https://github.com/vozlt/nginx-module-vts/compare/v0.2.4...HEAD
362 | [v0.2.4]: https://github.com/vozlt/nginx-module-vts/compare/v0.2.3...v0.2.4
363 | [v0.2.3]: https://github.com/vozlt/nginx-module-vts/compare/v0.2.2...v0.2.3
364 | [v0.2.2]: https://github.com/vozlt/nginx-module-vts/compare/v0.2.1...v0.2.2
365 | [v0.2.1]: https://github.com/vozlt/nginx-module-vts/compare/v0.2.0...v0.2.1
366 | [v0.2.0]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.18...v0.2.0
367 | [v0.1.18]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.17...v0.1.18
368 | [v0.1.17]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.16...v0.1.17
369 | [v0.1.16]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.15...v0.1.16
370 | [v0.1.15]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.14...v0.1.15
371 | [v0.1.14]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.13...v0.1.14
372 | [v0.1.13]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.12...v0.1.13
373 | [v0.1.12]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.11...v0.1.12
374 | [v0.1.11]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.10...v0.1.11
375 | [v0.1.10]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.9...v0.1.10
376 | [v0.1.9]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.8...v0.1.9
377 | [v0.1.8]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.7...v0.1.8
378 | [v0.1.7]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.6...v0.1.7
379 | [v0.1.6]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.5...v0.1.6
380 | [v0.1.5]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.4...v0.1.5
381 | [v0.1.4]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.3...v0.1.4
382 | [v0.1.3]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.2...v0.1.3
383 | [v0.1.2]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.1...v0.1.2
384 | [v0.1.1]: https://github.com/vozlt/nginx-module-vts/compare/v0.1.0...v0.1.1
385 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2015, YoungJoo.Kim
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice,
9 | this list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
21 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
24 | OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 | ngx_addon_name=ngx_http_vhost_traffic_status_module
2 | have=NGX_STAT_STUB . auto/have
3 |
4 | HTTP_VTS_SRCS=" \
5 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module.c \
6 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_variables.c \
7 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_string.c \
8 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_shm.c \
9 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_node.c \
10 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_filter.c \
11 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_control.c \
12 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_limit.c \
13 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display.c \
14 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_json.c \
15 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_prometheus.c \
16 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_set.c \
17 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_dump.c \
18 | "
19 |
20 | HTTP_VTS_DEPS=" \
21 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module.h \
22 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_variables.h \
23 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_string.h \
24 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_shm.h \
25 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_node.h \
26 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_filter.h \
27 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_control.h \
28 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_limit.h \
29 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display.h \
30 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_json.h \
31 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_prometheus.h \
32 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_set.h \
33 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_dump.h \
34 | $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module_html.h \
35 | "
36 | if test -n "$ngx_module_link"; then
37 | ngx_module_type=HTTP
38 | ngx_module_name=$ngx_addon_name
39 | ngx_module_srcs="$HTTP_VTS_SRCS"
40 | ngx_module_deps="$HTTP_VTS_DEPS"
41 |
42 | . auto/module
43 | else
44 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name"
45 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_VTS_SRCS"
46 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HTTP_VTS_DEPS"
47 | fi
48 |
49 | # vi:set ft=sh ts=4 sw=4 et fdm=marker:
50 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_control.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_CONTROL_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_CONTROL_H_INCLUDED_
9 |
10 |
11 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE 0
12 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS 1
13 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE 2
14 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET 3
15 |
16 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE 0
17 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL 1
18 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP 2
19 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE 3
20 |
21 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL "{" \
22 | "\"processingReturn\":%s," \
23 | "\"processingCommandString\":\"%V\"," \
24 | "\"processingGroupString\":\"%V\"," \
25 | "\"processingZoneString\":\"%V\"," \
26 | "\"processingCounts\":%ui" \
27 | "}"
28 |
29 |
30 | typedef struct {
31 | ngx_rbtree_node_t *node;
32 | } ngx_http_vhost_traffic_status_delete_t;
33 |
34 |
35 | typedef struct {
36 | ngx_http_request_t *r;
37 | ngx_uint_t command;
38 | ngx_int_t group;
39 | ngx_str_t *zone;
40 | ngx_str_t *arg_cmd;
41 | ngx_str_t *arg_group;
42 | ngx_str_t *arg_zone;
43 | ngx_str_t *arg_name;
44 | ngx_uint_t range;
45 | ngx_uint_t count;
46 | u_char **buf;
47 | } ngx_http_vhost_traffic_status_control_t;
48 |
49 |
50 | void ngx_http_vhost_traffic_status_node_control_range_set(
51 | ngx_http_vhost_traffic_status_control_t *control);
52 | void ngx_http_vhost_traffic_status_node_status(
53 | ngx_http_vhost_traffic_status_control_t *control);
54 | void ngx_http_vhost_traffic_status_node_delete(
55 | ngx_http_vhost_traffic_status_control_t *control);
56 | void ngx_http_vhost_traffic_status_node_reset(
57 | ngx_http_vhost_traffic_status_control_t *control);
58 |
59 | void ngx_http_vhost_traffic_status_node_upstream_lookup(
60 | ngx_http_vhost_traffic_status_control_t *control,
61 | ngx_http_upstream_server_t *us);
62 |
63 | #endif /* _NGX_HTTP_VTS_CONTROL_H_INCLUDED_ */
64 |
65 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
66 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_display.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_
9 |
10 |
11 | ngx_int_t ngx_http_vhost_traffic_status_display_get_upstream_nelts(
12 | ngx_http_request_t *r);
13 | ngx_int_t ngx_http_vhost_traffic_status_display_get_size(
14 | ngx_http_request_t *r, ngx_int_t format);
15 |
16 | u_char *ngx_http_vhost_traffic_status_display_get_time_queue(
17 | ngx_http_request_t *r,
18 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
19 | ngx_uint_t offset);
20 | u_char *ngx_http_vhost_traffic_status_display_get_time_queue_times(
21 | ngx_http_request_t *r,
22 | ngx_http_vhost_traffic_status_node_time_queue_t *q);
23 | u_char *ngx_http_vhost_traffic_status_display_get_time_queue_msecs(
24 | ngx_http_request_t *r,
25 | ngx_http_vhost_traffic_status_node_time_queue_t *q);
26 |
27 | u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket(
28 | ngx_http_request_t *r,
29 | ngx_http_vhost_traffic_status_node_histogram_bucket_t *b,
30 | ngx_uint_t offset, const char *fmt);
31 | u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs(
32 | ngx_http_request_t *r,
33 | ngx_http_vhost_traffic_status_node_histogram_bucket_t *b);
34 | u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters(
35 | ngx_http_request_t *r,
36 | ngx_http_vhost_traffic_status_node_histogram_bucket_t *q);
37 |
38 |
39 |
40 | char *ngx_http_vhost_traffic_status_display(ngx_conf_t *cf,
41 | ngx_command_t *cmd, void *conf);
42 |
43 |
44 | #endif /* _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_ */
45 |
46 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
47 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_display_json.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_
9 |
10 |
11 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S "{"
12 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_S "\"%V\":{"
13 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_S "\"%V\":["
14 |
15 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_E "]"
16 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_E "}"
17 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E "}"
18 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT ","
19 |
20 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_MAIN "\"hostName\":\"%V\"," \
21 | "\"moduleVersion\":\"%s\"," \
22 | "\"nginxVersion\":\"%s\"," \
23 | "\"loadMsec\":%M," \
24 | "\"nowMsec\":%M," \
25 | "\"connections\":{" \
26 | "\"active\":%uA," \
27 | "\"reading\":%uA," \
28 | "\"writing\":%uA," \
29 | "\"waiting\":%uA," \
30 | "\"accepted\":%uA," \
31 | "\"handled\":%uA," \
32 | "\"requests\":%uA" \
33 | "}," \
34 | "\"sharedZones\":{" \
35 | "\"name\":\"%V\"," \
36 | "\"maxSize\":%ui," \
37 | "\"usedSize\":%ui," \
38 | "\"usedNode\":%ui" \
39 | "},"
40 |
41 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_S "\"serverZones\":{"
42 |
43 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_START "\"%V\":{" \
44 | "\"requestCounter\":%uA," \
45 | "\"inBytes\":%uA," \
46 | "\"outBytes\":%uA,"
47 |
48 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_MIDDLE "\"responses\":{" \
49 | "\"1xx\":%uA," \
50 | "\"2xx\":%uA," \
51 | "\"3xx\":%uA," \
52 | "\"4xx\":%uA," \
53 | "\"5xx\":%uA"
54 |
55 | #if (NGX_HTTP_CACHE)
56 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END ",\"miss\":%uA," \
57 | "\"bypass\":%uA," \
58 | "\"expired\":%uA," \
59 | "\"stale\":%uA," \
60 | "\"updating\":%uA," \
61 | "\"revalidated\":%uA," \
62 | "\"hit\":%uA," \
63 | "\"scarce\":%uA" \
64 | "}," \
65 | "\"requestMsecCounter\":%uA," \
66 | "\"requestMsec\":%M," \
67 | "\"requestMsecs\":{" \
68 | "\"times\":[%s]," \
69 | "\"msecs\":[%s]" \
70 | "}," \
71 | "\"requestBuckets\":{" \
72 | "\"msecs\":[%s]," \
73 | "\"counters\":[%s]" \
74 | "}," \
75 | "\"overCounts\":{" \
76 | "\"maxIntegerSize\":%s," \
77 | "\"requestCounter\":%uA," \
78 | "\"inBytes\":%uA," \
79 | "\"outBytes\":%uA," \
80 | "\"1xx\":%uA," \
81 | "\"2xx\":%uA," \
82 | "\"3xx\":%uA," \
83 | "\"4xx\":%uA," \
84 | "\"5xx\":%uA," \
85 | "\"miss\":%uA," \
86 | "\"bypass\":%uA," \
87 | "\"expired\":%uA," \
88 | "\"stale\":%uA," \
89 | "\"updating\":%uA," \
90 | "\"revalidated\":%uA," \
91 | "\"hit\":%uA," \
92 | "\"scarce\":%uA," \
93 | "\"requestMsecCounter\":%uA" \
94 | "}" \
95 | "},"
96 | #else
97 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_END "}," \
98 | "\"requestMsecCounter\":%uA," \
99 | "\"requestMsec\":%M," \
100 | "\"requestMsecs\":{" \
101 | "\"times\":[%s]," \
102 | "\"msecs\":[%s]" \
103 | "}," \
104 | "\"requestBuckets\":{" \
105 | "\"msecs\":[%s]," \
106 | "\"counters\":[%s]" \
107 | "}," \
108 | "\"overCounts\":{" \
109 | "\"maxIntegerSize\":%s," \
110 | "\"requestCounter\":%uA," \
111 | "\"inBytes\":%uA," \
112 | "\"outBytes\":%uA," \
113 | "\"1xx\":%uA," \
114 | "\"2xx\":%uA," \
115 | "\"3xx\":%uA," \
116 | "\"4xx\":%uA," \
117 | "\"5xx\":%uA," \
118 | "\"requestMsecCounter\":%uA" \
119 | "}" \
120 | "},"
121 | #endif
122 |
123 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_START "\"statusCodes\":{"
124 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE ",\"%uA\":%uA"
125 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_OTHER_STATUS_CODE "\"other\":%uA"
126 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_STATUS_CODE_END "}, "
127 |
128 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_FILTER_S "\"filterZones\":{"
129 |
130 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S "\"upstreamZones\":{"
131 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM "{\"server\":\"%V\"," \
132 | "\"requestCounter\":%uA," \
133 | "\"inBytes\":%uA," \
134 | "\"outBytes\":%uA," \
135 | "\"responses\":{" \
136 | "\"1xx\":%uA," \
137 | "\"2xx\":%uA," \
138 | "\"3xx\":%uA," \
139 | "\"4xx\":%uA," \
140 | "\"5xx\":%uA" \
141 | "}," \
142 | "\"requestMsecCounter\":%uA," \
143 | "\"requestMsec\":%M," \
144 | "\"requestMsecs\":{" \
145 | "\"times\":[%s]," \
146 | "\"msecs\":[%s]" \
147 | "}," \
148 | "\"requestBuckets\":{" \
149 | "\"msecs\":[%s]," \
150 | "\"counters\":[%s]" \
151 | "}," \
152 | "\"responseMsecCounter\":%uA," \
153 | "\"responseMsec\":%M," \
154 | "\"responseMsecs\":{" \
155 | "\"times\":[%s]," \
156 | "\"msecs\":[%s]" \
157 | "}," \
158 | "\"responseBuckets\":{" \
159 | "\"msecs\":[%s]," \
160 | "\"counters\":[%s]" \
161 | "}," \
162 | "\"weight\":%ui," \
163 | "\"maxFails\":%ui," \
164 | "\"failTimeout\":%T," \
165 | "\"backup\":%s," \
166 | "\"down\":%s," \
167 | "\"overCounts\":{" \
168 | "\"maxIntegerSize\":%s," \
169 | "\"requestCounter\":%uA," \
170 | "\"inBytes\":%uA," \
171 | "\"outBytes\":%uA," \
172 | "\"1xx\":%uA," \
173 | "\"2xx\":%uA," \
174 | "\"3xx\":%uA," \
175 | "\"4xx\":%uA," \
176 | "\"5xx\":%uA," \
177 | "\"requestMsecCounter\":%uA," \
178 | "\"responseMsecCounter\":%uA" \
179 | "}" \
180 | "},"
181 |
182 | #if (NGX_HTTP_CACHE)
183 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE_S "\"cacheZones\":{"
184 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE "\"%V\":{" \
185 | "\"maxSize\":%uA," \
186 | "\"usedSize\":%uA," \
187 | "\"inBytes\":%uA," \
188 | "\"outBytes\":%uA," \
189 | "\"responses\":{" \
190 | "\"miss\":%uA," \
191 | "\"bypass\":%uA," \
192 | "\"expired\":%uA," \
193 | "\"stale\":%uA," \
194 | "\"updating\":%uA," \
195 | "\"revalidated\":%uA," \
196 | "\"hit\":%uA," \
197 | "\"scarce\":%uA" \
198 | "}," \
199 | "\"overCounts\":{" \
200 | "\"maxIntegerSize\":%s," \
201 | "\"inBytes\":%uA," \
202 | "\"outBytes\":%uA," \
203 | "\"miss\":%uA," \
204 | "\"bypass\":%uA," \
205 | "\"expired\":%uA," \
206 | "\"stale\":%uA," \
207 | "\"updating\":%uA," \
208 | "\"revalidated\":%uA," \
209 | "\"hit\":%uA," \
210 | "\"scarce\":%uA" \
211 | "}" \
212 | "},"
213 | #endif
214 |
215 |
216 | u_char *ngx_http_vhost_traffic_status_display_set_main(
217 | ngx_http_request_t *r, u_char *buf);
218 | u_char *ngx_http_vhost_traffic_status_display_set_server_node(
219 | ngx_http_request_t *r,
220 | u_char *buf, ngx_str_t *key,
221 | ngx_http_vhost_traffic_status_node_t *vtsn);
222 | u_char *ngx_http_vhost_traffic_status_display_set_server(
223 | ngx_http_request_t *r, u_char *buf,
224 | ngx_rbtree_node_t *node);
225 | u_char *ngx_http_vhost_traffic_status_display_set_filter_node(
226 | ngx_http_request_t *r, u_char *buf,
227 | ngx_http_vhost_traffic_status_node_t *vtsn);
228 | u_char *ngx_http_vhost_traffic_status_display_set_filter(
229 | ngx_http_request_t *r, u_char *buf,
230 | ngx_rbtree_node_t *node);
231 | u_char *ngx_http_vhost_traffic_status_display_set_upstream_node(
232 | ngx_http_request_t *r, u_char *buf,
233 | ngx_http_upstream_server_t *us,
234 | #if nginx_version > 1007001
235 | ngx_http_vhost_traffic_status_node_t *vtsn
236 | #else
237 | ngx_http_vhost_traffic_status_node_t *vtsn, ngx_str_t *name
238 | #endif
239 | );
240 | u_char *ngx_http_vhost_traffic_status_display_set_upstream_alone(
241 | ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node);
242 | u_char *ngx_http_vhost_traffic_status_display_set_upstream_group(
243 | ngx_http_request_t *r, u_char *buf);
244 |
245 | #if (NGX_HTTP_CACHE)
246 | u_char *ngx_http_vhost_traffic_status_display_set_cache_node(
247 | ngx_http_request_t *r, u_char *buf,
248 | ngx_http_vhost_traffic_status_node_t *vtsn);
249 | u_char *ngx_http_vhost_traffic_status_display_set_cache(
250 | ngx_http_request_t *r, u_char *buf,
251 | ngx_rbtree_node_t *node);
252 | #endif
253 |
254 | u_char *ngx_http_vhost_traffic_status_display_set(ngx_http_request_t *r,
255 | u_char *buf);
256 |
257 | void ngx_http_vhost_traffic_status_display_encode_uri(
258 | ngx_http_request_t *r, ngx_str_t *uri);
259 |
260 | #endif /* _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_ */
261 |
262 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
263 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_dump.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #include "ngx_http_vhost_traffic_status_module.h"
8 | #include "ngx_http_vhost_traffic_status_dump.h"
9 |
10 |
11 | static u_char NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD[] = { 0x53, 0x54, 0x56 };
12 |
13 |
14 | static ssize_t ngx_http_vhost_traffic_status_dump_header_read(ngx_file_t *file,
15 | ngx_http_vhost_traffic_status_dump_header_t *file_header);
16 | static ssize_t ngx_http_vhost_traffic_status_dump_header_write(ngx_event_t *ev,
17 | ngx_file_t *file);
18 | static void ngx_http_vhost_traffic_status_dump_node_write(ngx_event_t *ev,
19 | ngx_file_t *file, ngx_rbtree_node_t *node);
20 | static ngx_int_t ngx_http_vhost_traffic_status_dump_update_valid(ngx_event_t *ev);
21 | static ngx_int_t ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev,
22 | ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key);
23 |
24 |
25 | void
26 | ngx_http_vhost_traffic_status_file_lock(ngx_file_t *file)
27 | {
28 | ngx_err_t err = ngx_lock_fd(file->fd);
29 |
30 | if (err == 0) {
31 | return;
32 | }
33 |
34 | ngx_log_error(NGX_LOG_ALERT, file->log, err,
35 | ngx_lock_fd_n " \"%s\" failed", file->name.data);
36 | }
37 |
38 |
39 | void
40 | ngx_http_vhost_traffic_status_file_unlock(ngx_file_t *file)
41 | {
42 | ngx_err_t err = ngx_unlock_fd(file->fd);
43 |
44 | if (err == 0) {
45 | return;
46 | }
47 |
48 | ngx_log_error(NGX_LOG_ALERT, file->log, err,
49 | ngx_unlock_fd_n " \"%s\" failed", file->name.data);
50 | }
51 |
52 |
53 | void
54 | ngx_http_vhost_traffic_status_file_close(ngx_file_t *file)
55 | {
56 | if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
57 | ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno,
58 | ngx_close_file_n " \"%s\" failed", file->name.data);
59 | }
60 | }
61 |
62 |
63 | static ssize_t
64 | ngx_http_vhost_traffic_status_dump_header_read(ngx_file_t *file,
65 | ngx_http_vhost_traffic_status_dump_header_t *file_header)
66 | {
67 | ssize_t n;
68 |
69 | ngx_memzero(file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t));
70 |
71 | n = ngx_read_file(file, (u_char *) file_header,
72 | sizeof(ngx_http_vhost_traffic_status_dump_header_t), 0);
73 |
74 | return n;
75 | }
76 |
77 |
78 | static ssize_t
79 | ngx_http_vhost_traffic_status_dump_header_write(ngx_event_t *ev, ngx_file_t *file)
80 | {
81 | size_t len;
82 | ssize_t n;
83 | u_char *p;
84 | ngx_http_vhost_traffic_status_ctx_t *ctx;
85 | ngx_http_vhost_traffic_status_dump_header_t file_header;
86 |
87 | ctx = ev->data;
88 |
89 | ngx_memzero(&file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t));
90 |
91 | len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE)
92 | ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1
93 | : ctx->shm_name.len;
94 |
95 | p = file_header.name;
96 | p = ngx_cpymem(p, ctx->shm_name.data, len);
97 | file_header.time = ngx_http_vhost_traffic_status_current_msec();
98 | file_header.version = nginx_version;
99 |
100 | n = ngx_write_fd(file->fd, &file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t));
101 |
102 | return n;
103 | }
104 |
105 |
106 | static void
107 | ngx_http_vhost_traffic_status_dump_node_write(ngx_event_t *ev, ngx_file_t *file,
108 | ngx_rbtree_node_t *node)
109 | {
110 | ngx_http_vhost_traffic_status_ctx_t *ctx;
111 | ngx_http_vhost_traffic_status_node_t *volatile vtsn;
112 |
113 | ctx = ev->data;
114 |
115 | if (node != ctx->rbtree->sentinel) {
116 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
117 |
118 | (void) ngx_write_fd(file->fd, vtsn, sizeof(ngx_http_vhost_traffic_status_node_t));
119 | (void) ngx_write_fd(file->fd, vtsn->data, vtsn->len);
120 | (void) ngx_write_fd(file->fd, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD,
121 | sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD));
122 |
123 | ngx_http_vhost_traffic_status_dump_node_write(ev, file, node->left);
124 | ngx_http_vhost_traffic_status_dump_node_write(ev, file, node->right);
125 | }
126 | }
127 |
128 |
129 | static ngx_int_t
130 | ngx_http_vhost_traffic_status_dump_update_valid(ngx_event_t *ev)
131 | {
132 | size_t len;
133 | ssize_t n;
134 | ngx_fd_t fd;
135 | ngx_int_t rc;
136 | ngx_msec_t current_msec;
137 | ngx_file_t file;
138 | ngx_http_vhost_traffic_status_ctx_t *ctx;
139 | ngx_http_vhost_traffic_status_dump_header_t file_header;
140 |
141 | ctx = ev->data;
142 |
143 | fd = ngx_open_file(ctx->dump_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
144 | if (fd == NGX_INVALID_FILE) {
145 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, ngx_errno,
146 | ngx_open_file_n " \"%s\" failed", ctx->dump_file.data);
147 | return NGX_OK;
148 | }
149 |
150 | file.fd = fd;
151 | file.name = ctx->dump_file;
152 | file.log = ev->log;
153 |
154 | n = ngx_http_vhost_traffic_status_dump_header_read(&file, &file_header);
155 |
156 | ngx_http_vhost_traffic_status_file_close(&file);
157 |
158 | if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) {
159 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
160 | "dump_update_valid::dump_header_read() size:%z failed", n);
161 | return NGX_OK;
162 | }
163 |
164 | len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE)
165 | ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1
166 | : ctx->shm_name.len;
167 |
168 | if (ngx_strncmp(ctx->shm_name.data, file_header.name, len) != 0) {
169 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
170 | "dump_update_valid::dump_header_read() name[%z]:\"%s\" failed",
171 | len, file_header.name);
172 | return NGX_OK;
173 | }
174 |
175 | current_msec = ngx_http_vhost_traffic_status_current_msec();
176 |
177 | rc = ((current_msec - file_header.time) > ctx->dump_period) ? NGX_OK : NGX_ERROR;
178 |
179 | return rc;
180 | }
181 |
182 |
183 | ngx_int_t
184 | ngx_http_vhost_traffic_status_dump_execute(ngx_event_t *ev)
185 | {
186 | u_char *name;
187 | ssize_t n;
188 | ngx_fd_t fd;
189 | ngx_file_t file;
190 | ngx_http_vhost_traffic_status_ctx_t *ctx;
191 |
192 | ctx = ev->data;
193 |
194 | name = ctx->dump_file.data;
195 |
196 | fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS);
197 |
198 | if (fd == NGX_INVALID_FILE) {
199 | ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
200 | ngx_open_file_n " \"%s\" failed", name);
201 | return NGX_ERROR;
202 | }
203 |
204 | file.fd = fd;
205 | file.name = ctx->dump_file;
206 | file.log = ev->log;
207 |
208 | ngx_http_vhost_traffic_status_file_lock(&file);
209 |
210 | n = ngx_http_vhost_traffic_status_dump_header_write(ev, &file);
211 | if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) {
212 | ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
213 | "dump_execute::dump_header_write() failed");
214 |
215 | ngx_http_vhost_traffic_status_file_unlock(&file);
216 | ngx_http_vhost_traffic_status_file_close(&file);
217 |
218 | return NGX_ERROR;
219 | }
220 |
221 | ngx_http_vhost_traffic_status_dump_node_write(ev, &file, ctx->rbtree->root);
222 |
223 | ngx_http_vhost_traffic_status_file_unlock(&file);
224 | ngx_http_vhost_traffic_status_file_close(&file);
225 |
226 | return NGX_OK;
227 | }
228 |
229 |
230 | void
231 | ngx_http_vhost_traffic_status_dump_handler(ngx_event_t *ev)
232 | {
233 | ngx_int_t rc;
234 |
235 | if (ngx_exiting) {
236 | return;
237 | }
238 |
239 | rc = ngx_http_vhost_traffic_status_dump_update_valid(ev);
240 | if (rc != NGX_OK) {
241 | goto invalid;
242 | }
243 |
244 | rc = ngx_http_vhost_traffic_status_dump_execute(ev);
245 | if (rc != NGX_OK) {
246 | ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
247 | "dump_handler::dump_header_execute() failed");
248 | }
249 |
250 | invalid:
251 |
252 | ngx_add_timer(ev, 1000);
253 | }
254 |
255 |
256 | static ngx_int_t
257 | ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev,
258 | ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key)
259 | {
260 | size_t size;
261 | uint32_t hash;
262 | ngx_slab_pool_t *shpool;
263 | ngx_rbtree_node_t *node;
264 | ngx_http_vhost_traffic_status_ctx_t *ctx;
265 | ngx_http_vhost_traffic_status_node_t *vtsn;
266 |
267 | ctx = ev->data;
268 |
269 | if (key->len == 0) {
270 | return NGX_ERROR;
271 | }
272 |
273 | shpool = (ngx_slab_pool_t *) ctx->shm_zone->shm.addr;
274 |
275 | ngx_shmtx_lock(&shpool->mutex);
276 |
277 | /* find node */
278 | hash = ngx_crc32_short(key->data, key->len);
279 |
280 | node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, key, hash);
281 |
282 | /* copy node */
283 | if (node == NULL) {
284 | size = offsetof(ngx_rbtree_node_t, color)
285 | + offsetof(ngx_http_vhost_traffic_status_node_t, data)
286 | + key->len;
287 |
288 | node = ngx_slab_alloc_locked(shpool, size);
289 | if (node == NULL) {
290 | ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
291 | "dump_restore_add_node::ngx_slab_alloc_locked() failed");
292 |
293 | ngx_shmtx_unlock(&shpool->mutex);
294 | return NGX_ERROR;
295 | }
296 |
297 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
298 |
299 | node->key = hash;
300 |
301 | *vtsn = *ovtsn;
302 |
303 | ngx_memcpy(vtsn->data, key->data, key->len);
304 |
305 | ngx_rbtree_insert(ctx->rbtree, node);
306 | }
307 |
308 | ngx_shmtx_unlock(&shpool->mutex);
309 |
310 | return NGX_OK;
311 | }
312 |
313 |
314 | void
315 | ngx_http_vhost_traffic_status_dump_restore(ngx_event_t *ev)
316 | {
317 | off_t offset;
318 | size_t len;
319 | ssize_t n;
320 | u_char *buf, *pad;
321 | ngx_fd_t fd;
322 | ngx_str_t key;
323 | ngx_int_t rc;
324 | ngx_file_t file;
325 | ngx_http_vhost_traffic_status_ctx_t *ctx;
326 | ngx_http_vhost_traffic_status_node_t vtsn;
327 | ngx_http_vhost_traffic_status_dump_header_t file_header;
328 |
329 | ctx = ev->data;
330 |
331 | fd = ngx_open_file(ctx->dump_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
332 | if (fd == NGX_INVALID_FILE) {
333 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, ngx_errno,
334 | ngx_open_file_n " \"%s\" failed", ctx->dump_file.data);
335 | return;
336 | }
337 |
338 | file.fd = fd;
339 | file.name = ctx->dump_file;
340 | file.log = ev->log;
341 |
342 | n = ngx_http_vhost_traffic_status_dump_header_read(&file, &file_header);
343 |
344 | if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) {
345 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
346 | "dump_restore::dump_header_read() size:%z failed", n);
347 | ngx_http_vhost_traffic_status_file_close(&file);
348 | return;
349 | }
350 |
351 | len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE)
352 | ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1
353 | : ctx->shm_name.len;
354 |
355 | if (ngx_strncmp(ctx->shm_name.data, file_header.name, len) != 0) {
356 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
357 | "dump_restore::dump_header_read() name[%z]:\"%s\" failed",
358 | len, file_header.name);
359 | ngx_http_vhost_traffic_status_file_close(&file);
360 | return;
361 | }
362 |
363 | buf = ngx_pcalloc(ngx_cycle->pool, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE);
364 | pad = ngx_pcalloc(ngx_cycle->pool, sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD));
365 | if (buf == NULL || pad == NULL) {
366 | ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
367 | "dump_restore::ngx_pcalloc() failed");
368 | ngx_http_vhost_traffic_status_file_close(&file);
369 | return;
370 | }
371 |
372 | offset = n;
373 |
374 | for ( ;; ) {
375 | ngx_memzero(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE);
376 |
377 | /* read: node */
378 | n = ngx_read_file(&file, (u_char *) &vtsn,
379 | sizeof(ngx_http_vhost_traffic_status_node_t), offset);
380 |
381 | if (n == NGX_ERROR || n == 0
382 | || n != sizeof(ngx_http_vhost_traffic_status_node_t)) {
383 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
384 | "dump_restore::ngx_read_file() node size:%z failed", n);
385 | break;
386 | }
387 |
388 | if (vtsn.len > NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE) {
389 | offset += vtsn.len + sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD);
390 | continue;
391 | }
392 |
393 | /* read: data */
394 | offset += n;
395 | n = ngx_read_file(&file, buf, vtsn.len, offset);
396 | if (n >= 0 && vtsn.len <= SSIZE_MAX && n != (ssize_t) vtsn.len) {
397 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
398 | "dump_restore::ngx_read_file() read:%z, data:%z failed",
399 | n, vtsn.len);
400 | break;
401 | }
402 |
403 | /* read: pad */
404 | offset += n;
405 | n = ngx_read_file(&file, pad,
406 | sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD),
407 | offset);
408 | if (n == NGX_ERROR || n == 0
409 | || n != sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD))
410 | {
411 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
412 | "dump_restore::ngx_read_file() pad size:%z failed", n);
413 | break;
414 | }
415 |
416 | if (ngx_memcmp(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD, pad, n) != 0) {
417 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
418 | "dump_restore::ngx_read_file() pad does not match");
419 | break;
420 | }
421 |
422 | /* push: node */
423 | key.len = vtsn.len;
424 | key.data = buf;
425 |
426 | rc = ngx_http_vhost_traffic_status_dump_restore_add_node(ev, &vtsn, &key);
427 | if (rc != NGX_OK) {
428 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
429 | "dump_restore::dump_restore_add_node() failed");
430 | break;
431 | }
432 |
433 | offset += n;
434 | }
435 |
436 | ngx_http_vhost_traffic_status_file_close(&file);
437 | }
438 |
439 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
440 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_dump.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_DUMP_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_DUMP_H_INCLUDED_
9 |
10 |
11 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE 128
12 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE 1024
13 |
14 |
15 | typedef struct {
16 | u_char name[NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE];
17 | ngx_msec_t time;
18 | ngx_uint_t version;
19 | } ngx_http_vhost_traffic_status_dump_header_t;
20 |
21 |
22 | void ngx_http_vhost_traffic_status_file_lock(ngx_file_t *file);
23 | void ngx_http_vhost_traffic_status_file_unlock(ngx_file_t *file);
24 | void ngx_http_vhost_traffic_status_file_close(ngx_file_t *file);
25 |
26 | ngx_int_t ngx_http_vhost_traffic_status_dump_execute(ngx_event_t *ev);
27 | void ngx_http_vhost_traffic_status_dump_handler(ngx_event_t *ev);
28 | void ngx_http_vhost_traffic_status_dump_restore(ngx_event_t *ev);
29 |
30 |
31 | #endif /* _NGX_HTTP_VTS_DUMP_H_INCLUDED_ */
32 |
33 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
34 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_filter.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #include "ngx_http_vhost_traffic_status_module.h"
8 | #include "ngx_http_vhost_traffic_status_filter.h"
9 |
10 |
11 | int ngx_libc_cdecl
12 | ngx_http_traffic_status_filter_cmp_hashs(const void *one, const void *two)
13 | {
14 | ngx_http_vhost_traffic_status_filter_uniq_t *first =
15 | (ngx_http_vhost_traffic_status_filter_uniq_t *) one;
16 | ngx_http_vhost_traffic_status_filter_uniq_t *second =
17 | (ngx_http_vhost_traffic_status_filter_uniq_t *) two;
18 |
19 | return (first->hash - second->hash);
20 | }
21 |
22 |
23 | int ngx_libc_cdecl
24 | ngx_http_traffic_status_filter_cmp_keys(const void *one, const void *two)
25 | {
26 | ngx_http_vhost_traffic_status_filter_key_t *first =
27 | (ngx_http_vhost_traffic_status_filter_key_t *) one;
28 | ngx_http_vhost_traffic_status_filter_key_t *second =
29 | (ngx_http_vhost_traffic_status_filter_key_t *) two;
30 |
31 | return (int) ngx_strcmp(first->key.data, second->key.data);
32 | }
33 |
34 |
35 | ngx_int_t
36 | ngx_http_vhost_traffic_status_filter_unique(ngx_pool_t *pool, ngx_array_t **keys)
37 | {
38 | uint32_t hash;
39 | u_char *p;
40 | ngx_str_t key;
41 | ngx_uint_t i, n;
42 | ngx_array_t *uniqs, *filter_keys;
43 | ngx_http_vhost_traffic_status_filter_t *filter, *filters;
44 | ngx_http_vhost_traffic_status_filter_uniq_t *filter_uniqs;
45 |
46 | if (*keys == NULL) {
47 | return NGX_OK;
48 | }
49 |
50 | uniqs = ngx_array_create(pool, 1,
51 | sizeof(ngx_http_vhost_traffic_status_filter_uniq_t));
52 | if (uniqs == NULL) {
53 | return NGX_ERROR;
54 | }
55 |
56 | /* init array */
57 | filter_keys = NULL;
58 | filter_uniqs = NULL;
59 |
60 | filters = (*keys)->elts;
61 | n = (*keys)->nelts;
62 |
63 | for (i = 0; i < n; i++) {
64 | key.len = filters[i].filter_key.value.len
65 | + filters[i].filter_name.value.len;
66 | key.data = ngx_pcalloc(pool, key.len);
67 | if (key.data == NULL) {
68 | return NGX_ERROR;
69 | }
70 |
71 | p = key.data;
72 | p = ngx_cpymem(p, filters[i].filter_key.value.data,
73 | filters[i].filter_key.value.len);
74 | ngx_memcpy(p, filters[i].filter_name.value.data,
75 | filters[i].filter_name.value.len);
76 | hash = ngx_crc32_short(key.data, key.len);
77 |
78 | filter_uniqs = ngx_array_push(uniqs);
79 | if (filter_uniqs == NULL) {
80 | return NGX_ERROR;
81 | }
82 |
83 | filter_uniqs->hash = hash;
84 | filter_uniqs->index = i;
85 |
86 | if (p != NULL) {
87 | ngx_pfree(pool, key.data);
88 | }
89 | }
90 |
91 | filter_uniqs = uniqs->elts;
92 | n = uniqs->nelts;
93 |
94 | ngx_qsort(filter_uniqs, (size_t) n,
95 | sizeof(ngx_http_vhost_traffic_status_filter_uniq_t),
96 | ngx_http_traffic_status_filter_cmp_hashs);
97 |
98 | hash = 0;
99 | for (i = 0; i < n; i++) {
100 | if (filter_uniqs[i].hash == hash) {
101 | continue;
102 | }
103 |
104 | hash = filter_uniqs[i].hash;
105 |
106 | if (filter_keys == NULL) {
107 | filter_keys = ngx_array_create(pool, 1,
108 | sizeof(ngx_http_vhost_traffic_status_filter_t));
109 | if (filter_keys == NULL) {
110 | return NGX_ERROR;
111 | }
112 | }
113 |
114 | filter = ngx_array_push(filter_keys);
115 | if (filter == NULL) {
116 | return NGX_ERROR;
117 | }
118 |
119 | ngx_memcpy(filter, &filters[filter_uniqs[i].index],
120 | sizeof(ngx_http_vhost_traffic_status_filter_t));
121 |
122 | }
123 |
124 | if ((*keys)->nelts != filter_keys->nelts) {
125 | *keys = filter_keys;
126 | }
127 |
128 | return NGX_OK;
129 | }
130 |
131 |
132 | ngx_int_t
133 | ngx_http_vhost_traffic_status_filter_get_keys(ngx_http_request_t *r,
134 | ngx_array_t **filter_keys, ngx_rbtree_node_t *node)
135 | {
136 | ngx_int_t rc;
137 | ngx_str_t key;
138 | ngx_http_vhost_traffic_status_ctx_t *ctx;
139 | ngx_http_vhost_traffic_status_node_t *vtsn;
140 | ngx_http_vhost_traffic_status_filter_key_t *keys;
141 |
142 | ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);
143 |
144 | if (node != ctx->rbtree->sentinel) {
145 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
146 |
147 | if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) {
148 | key.data = vtsn->data;
149 | key.len = vtsn->len;
150 |
151 | rc = ngx_http_vhost_traffic_status_node_position_key(&key, 1);
152 | if (rc != NGX_OK) {
153 | goto next;
154 | }
155 |
156 | if (*filter_keys == NULL) {
157 | *filter_keys = ngx_array_create(r->pool, 1,
158 | sizeof(ngx_http_vhost_traffic_status_filter_key_t));
159 |
160 | if (*filter_keys == NULL) {
161 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
162 | "filter_get_keys::ngx_array_create() failed");
163 | return NGX_ERROR;
164 | }
165 | }
166 |
167 | keys = ngx_array_push(*filter_keys);
168 | if (keys == NULL) {
169 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
170 | "filter_get_keys::ngx_array_push() failed");
171 | return NGX_ERROR;
172 | }
173 |
174 | keys->key.len = key.len;
175 | /* 1 byte for terminating '\0' for ngx_strcmp() */
176 | keys->key.data = ngx_pcalloc(r->pool, key.len + 1);
177 | if (keys->key.data == NULL) {
178 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
179 | "filter_get_keys::ngx_pcalloc() failed");
180 | }
181 |
182 | ngx_memcpy(keys->key.data, key.data, key.len);
183 | }
184 | next:
185 | rc = ngx_http_vhost_traffic_status_filter_get_keys(r, filter_keys, node->left);
186 | if (rc != NGX_OK) {
187 | return rc;
188 | }
189 |
190 | rc = ngx_http_vhost_traffic_status_filter_get_keys(r, filter_keys, node->right);
191 | if (rc != NGX_OK) {
192 | return rc;
193 | }
194 | }
195 |
196 | return NGX_OK;
197 | }
198 |
199 |
200 | ngx_int_t
201 | ngx_http_vhost_traffic_status_filter_get_nodes(ngx_http_request_t *r,
202 | ngx_array_t **filter_nodes, ngx_str_t *name,
203 | ngx_rbtree_node_t *node)
204 | {
205 | ngx_int_t rc;
206 | ngx_str_t key;
207 | ngx_http_vhost_traffic_status_ctx_t *ctx;
208 | ngx_http_vhost_traffic_status_node_t *vtsn;
209 | ngx_http_vhost_traffic_status_filter_node_t *nodes;
210 |
211 | ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);
212 |
213 | if (node != ctx->rbtree->sentinel) {
214 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
215 |
216 | if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) {
217 | key.data = vtsn->data;
218 | key.len = vtsn->len;
219 |
220 | rc = ngx_http_vhost_traffic_status_node_position_key(&key, 1);
221 | if (rc != NGX_OK) {
222 | goto next;
223 | }
224 |
225 | if (name->len != key.len) {
226 | goto next;
227 | }
228 |
229 | if (ngx_strncmp(name->data, key.data, key.len) != 0) {
230 | goto next;
231 | }
232 |
233 | if (*filter_nodes == NULL) {
234 | *filter_nodes = ngx_array_create(r->pool, 1,
235 | sizeof(ngx_http_vhost_traffic_status_filter_node_t));
236 |
237 | if (*filter_nodes == NULL) {
238 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
239 | "filter_get_nodes::ngx_array_create() failed");
240 | return NGX_ERROR;
241 | }
242 | }
243 |
244 | nodes = ngx_array_push(*filter_nodes);
245 | if (nodes == NULL) {
246 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
247 | "filter_get_nodes::ngx_array_push() failed");
248 | return NGX_ERROR;
249 | }
250 |
251 | nodes->node = vtsn;
252 | }
253 | next:
254 | rc = ngx_http_vhost_traffic_status_filter_get_nodes(r, filter_nodes, name, node->left);
255 | if (rc != NGX_OK) {
256 | return rc;
257 | }
258 |
259 | rc = ngx_http_vhost_traffic_status_filter_get_nodes(r, filter_nodes, name, node->right);
260 | if (rc != NGX_OK) {
261 | return rc;
262 | }
263 | }
264 |
265 | return NGX_OK;
266 | }
267 |
268 |
269 | ngx_int_t
270 | ngx_http_vhost_traffic_status_filter_max_node_match(ngx_http_request_t *r,
271 | ngx_str_t *filter)
272 | {
273 | ngx_uint_t i, n;
274 | ngx_http_vhost_traffic_status_ctx_t *ctx;
275 | ngx_http_vhost_traffic_status_filter_match_t *matches;
276 |
277 | ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);
278 |
279 | if (ctx->filter_max_node_matches == NULL) {
280 | return NGX_OK;
281 | }
282 |
283 | matches = ctx->filter_max_node_matches->elts;
284 | n = ctx->filter_max_node_matches->nelts;
285 |
286 | /* disabled */
287 | if (n == 0) {
288 | return NGX_OK;
289 | }
290 |
291 | for (i = 0; i < n; i++) {
292 | if (ngx_strncmp(filter->data, matches[i].match.data, matches[i].match.len) == 0) {
293 | return NGX_OK;
294 | }
295 | }
296 |
297 | return NGX_ERROR;
298 | }
299 |
300 |
301 | char *
302 | ngx_http_vhost_traffic_status_filter_by_set_key(ngx_conf_t *cf, ngx_command_t *cmd,
303 | void *conf)
304 | {
305 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf;
306 |
307 | ngx_str_t *value, name;
308 | ngx_array_t *filter_keys;
309 | ngx_http_compile_complex_value_t ccv;
310 | ngx_http_vhost_traffic_status_ctx_t *ctx;
311 | ngx_http_vhost_traffic_status_filter_t *filter;
312 |
313 | ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module);
314 | if (ctx == NULL) {
315 | return NGX_CONF_ERROR;
316 | }
317 |
318 | value = cf->args->elts;
319 | if (value[1].len == 0) {
320 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty key pattern");
321 | return NGX_CONF_ERROR;
322 | }
323 |
324 | filter_keys = (cf->cmd_type == NGX_HTTP_MAIN_CONF) ? ctx->filter_keys : vtscf->filter_keys;
325 | if (filter_keys == NULL) {
326 | filter_keys = ngx_array_create(cf->pool, 1,
327 | sizeof(ngx_http_vhost_traffic_status_filter_t));
328 | if (filter_keys == NULL) {
329 | return NGX_CONF_ERROR;
330 | }
331 | }
332 |
333 | filter = ngx_array_push(filter_keys);
334 | if (filter == NULL) {
335 | return NGX_CONF_ERROR;
336 | }
337 |
338 | /* first argument process */
339 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
340 |
341 | ccv.cf = cf;
342 | ccv.value = &value[1];
343 | ccv.complex_value = &filter->filter_key;
344 |
345 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
346 | return NGX_CONF_ERROR;
347 | }
348 |
349 | /* second argument process */
350 | if (cf->args->nelts == 3) {
351 | name = value[2];
352 |
353 | } else {
354 | ngx_str_set(&name, "");
355 | }
356 |
357 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
358 |
359 | ccv.cf = cf;
360 | ccv.value = &name;
361 | ccv.complex_value = &filter->filter_name;
362 |
363 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
364 | return NGX_CONF_ERROR;
365 | }
366 |
367 | if (cf->cmd_type == NGX_HTTP_MAIN_CONF) {
368 | ctx->filter_keys = filter_keys;
369 |
370 | } else {
371 | vtscf->filter_keys = filter_keys;
372 | }
373 |
374 | return NGX_CONF_OK;
375 | }
376 |
377 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
378 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_filter.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_FILTER_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_FILTER_H_INCLUDED_
9 |
10 |
11 | typedef struct {
12 | ngx_http_complex_value_t filter_key;
13 | ngx_http_complex_value_t filter_name;
14 | } ngx_http_vhost_traffic_status_filter_t;
15 |
16 |
17 | typedef struct {
18 | ngx_str_t key;
19 | } ngx_http_vhost_traffic_status_filter_key_t;
20 |
21 |
22 | typedef struct {
23 | uint32_t hash;
24 | ngx_uint_t index;
25 | } ngx_http_vhost_traffic_status_filter_uniq_t;
26 |
27 |
28 | typedef struct {
29 | ngx_http_vhost_traffic_status_node_t *node;
30 | } ngx_http_vhost_traffic_status_filter_node_t;
31 |
32 |
33 | typedef struct {
34 | ngx_str_t match;
35 | } ngx_http_vhost_traffic_status_filter_match_t;
36 |
37 |
38 | int ngx_libc_cdecl ngx_http_traffic_status_filter_cmp_hashs(
39 | const void *one, const void *two);
40 | int ngx_libc_cdecl ngx_http_traffic_status_filter_cmp_keys(
41 | const void *one, const void *two);
42 | ngx_int_t ngx_http_vhost_traffic_status_filter_unique(
43 | ngx_pool_t *pool, ngx_array_t **keys);
44 | ngx_int_t ngx_http_vhost_traffic_status_filter_get_keys(
45 | ngx_http_request_t *r, ngx_array_t **filter_keys,
46 | ngx_rbtree_node_t *node);
47 | ngx_int_t ngx_http_vhost_traffic_status_filter_get_nodes(
48 | ngx_http_request_t *r, ngx_array_t **filter_nodes,
49 | ngx_str_t *name, ngx_rbtree_node_t *node);
50 | ngx_int_t ngx_http_vhost_traffic_status_filter_max_node_match(
51 | ngx_http_request_t *r, ngx_str_t *filter);
52 |
53 | char *ngx_http_vhost_traffic_status_filter_by_set_key(ngx_conf_t *cf,
54 | ngx_command_t *cmd, void *conf);
55 |
56 |
57 | #endif /* _NGX_HTTP_VTS_FILTER_H_INCLUDED_ */
58 |
59 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
60 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_limit.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #include "ngx_http_vhost_traffic_status_module.h"
8 | #include "ngx_http_vhost_traffic_status_filter.h"
9 | #include "ngx_http_vhost_traffic_status_limit.h"
10 |
11 |
12 | ngx_int_t
13 | ngx_http_vhost_traffic_status_limit_handler(ngx_http_request_t *r)
14 | {
15 | ngx_int_t rc;
16 | ngx_http_vhost_traffic_status_ctx_t *ctx;
17 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf;
18 |
19 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
20 | "http vts limit handler");
21 |
22 | ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);
23 |
24 | vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module);
25 |
26 | if (!ctx->enable || !vtscf->limit || vtscf->bypass_limit) {
27 | return NGX_DECLINED;
28 | }
29 |
30 | /* limit traffic of server */
31 | rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, ctx->limit_traffics);
32 | if (rc != NGX_DECLINED) {
33 | return rc;
34 | }
35 |
36 | rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, vtscf->limit_traffics);
37 | if (rc != NGX_DECLINED) {
38 | return rc;
39 | }
40 |
41 | /* limit traffic of filter */
42 | rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, ctx->limit_filter_traffics);
43 | if (rc != NGX_DECLINED) {
44 | return rc;
45 | }
46 |
47 | rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, vtscf->limit_filter_traffics);
48 | if (rc != NGX_DECLINED) {
49 | return rc;
50 | }
51 |
52 | return NGX_DECLINED;
53 | }
54 |
55 |
56 | ngx_int_t
57 | ngx_http_vhost_traffic_status_limit_handler_traffic(ngx_http_request_t *r,
58 | ngx_array_t *traffics)
59 | {
60 | unsigned type;
61 | ngx_str_t variable, key, dst;
62 | ngx_int_t rc;
63 | ngx_uint_t i, n;
64 | ngx_atomic_t traffic_used;
65 | ngx_slab_pool_t *shpool;
66 | ngx_rbtree_node_t *node;
67 | ngx_http_vhost_traffic_status_node_t *vtsn;
68 | ngx_http_vhost_traffic_status_limit_t *limits;
69 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf;
70 |
71 | vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module);
72 |
73 | rc = NGX_DECLINED;
74 |
75 | if (traffics == NULL) {
76 | return rc;
77 | }
78 |
79 | shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;
80 |
81 | ngx_shmtx_lock(&shpool->mutex);
82 |
83 | limits = traffics->elts;
84 | n = traffics->nelts;
85 |
86 | for (i = 0; i < n; i++) {
87 | if (limits[i].variable.value.len <= 0) {
88 | continue;
89 | }
90 |
91 | /* init */
92 | traffic_used = 0;
93 | variable.len = 0;
94 | key.len = 0;
95 | dst.len = 0;
96 | type = limits[i].type;
97 |
98 | if (ngx_http_complex_value(r, &limits[i].variable, &variable) != NGX_OK) {
99 | goto done;
100 | }
101 |
102 | if (variable.len == 0) {
103 | continue;
104 | }
105 |
106 | /* traffic of filter */
107 | if (limits[i].key.value.len > 0) {
108 | if (ngx_http_complex_value(r, &limits[i].key, &key) != NGX_OK) {
109 | goto done;
110 | }
111 |
112 | if (key.len == 0) {
113 | continue;
114 | }
115 |
116 | node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0);
117 |
118 | if (node == NULL) {
119 | continue;
120 | }
121 |
122 | vtscf->node_caches[type] = node;
123 |
124 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
125 |
126 | traffic_used = (ngx_atomic_t) ngx_http_vhost_traffic_status_node_member(vtsn, &variable);
127 |
128 | /* traffic of server */
129 | } else {
130 | ngx_http_vhost_traffic_status_find_name(r, &dst);
131 |
132 | if (ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type)
133 | != NGX_OK || key.len == 0)
134 | {
135 | goto done;
136 | }
137 |
138 | node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0);
139 |
140 | if (node == NULL) {
141 | continue;
142 | }
143 |
144 | vtscf->node_caches[type] = node;
145 |
146 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
147 |
148 | traffic_used = (ngx_atomic_t) ngx_http_vhost_traffic_status_node_member(vtsn, &variable);
149 | }
150 |
151 | if (traffic_used > limits[i].size) {
152 | rc = limits[i].code;
153 | goto done;
154 | }
155 | }
156 |
157 | done:
158 |
159 | ngx_shmtx_unlock(&shpool->mutex);
160 |
161 | return rc;
162 | }
163 |
164 |
165 | char *
166 | ngx_http_vhost_traffic_status_limit_traffic(ngx_conf_t *cf, ngx_command_t *cmd,
167 | void *conf)
168 | {
169 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf;
170 |
171 | u_char *p;
172 | off_t size;
173 | ngx_str_t *value, s;
174 | ngx_array_t *limit_traffics;
175 | ngx_http_compile_complex_value_t ccv;
176 | ngx_http_vhost_traffic_status_ctx_t *ctx;
177 | ngx_http_vhost_traffic_status_limit_t *traffic;
178 |
179 | ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module);
180 | if (ctx == NULL) {
181 | return NGX_CONF_ERROR;
182 | }
183 |
184 | value = cf->args->elts;
185 | if (value[1].len == 0) {
186 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() empty value pattern");
187 | return NGX_CONF_ERROR;
188 | }
189 |
190 | if (value[1].len > 5 && ngx_strstrn(value[1].data, "$vts_", 5 - 1)) {
191 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() $vts_* is not allowed here");
192 | return NGX_CONF_ERROR;
193 | }
194 |
195 | p = (u_char *) ngx_strchr(value[1].data, ':');
196 | if (p == NULL) {
197 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() empty size pattern");
198 | return NGX_CONF_ERROR;
199 | }
200 |
201 | s.data = p + 1;
202 | s.len = value[1].data + value[1].len - s.data;
203 |
204 | size = ngx_parse_offset(&s);
205 | if (size == NGX_ERROR) {
206 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
207 | "limit_traffic() invalid limit size \"%V\"", &value[1]);
208 | return NGX_CONF_ERROR;
209 | }
210 |
211 | limit_traffics = (cf->cmd_type == NGX_HTTP_MAIN_CONF)
212 | ? ctx->limit_traffics
213 | : vtscf->limit_traffics;
214 | if (limit_traffics == NULL) {
215 | limit_traffics = ngx_array_create(cf->pool, 1,
216 | sizeof(ngx_http_vhost_traffic_status_limit_t));
217 | if (limit_traffics == NULL) {
218 | return NGX_CONF_ERROR;
219 | }
220 | }
221 |
222 | traffic = ngx_array_push(limit_traffics);
223 | if (traffic == NULL) {
224 | return NGX_CONF_ERROR;
225 | }
226 |
227 | value[1].len = p - value[1].data;
228 |
229 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
230 |
231 | ccv.cf = cf;
232 | ccv.value = &value[1];
233 | ccv.complex_value = &traffic->variable;
234 |
235 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
236 | return NGX_CONF_ERROR;
237 | }
238 |
239 | traffic->size = (ngx_atomic_t) size;
240 |
241 | traffic->code = (cf->args->nelts == 3)
242 | ? (ngx_uint_t) ngx_atoi(value[2].data, value[2].len)
243 | : NGX_HTTP_SERVICE_UNAVAILABLE;
244 |
245 | traffic->type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO;
246 |
247 | traffic->key.value.len = 0;
248 |
249 | if (cf->cmd_type == NGX_HTTP_MAIN_CONF) {
250 | ctx->limit_traffics = limit_traffics;
251 |
252 | } else {
253 | vtscf->limit_traffics = limit_traffics;
254 | }
255 |
256 | return NGX_CONF_OK;
257 | }
258 |
259 |
260 | char *
261 | ngx_http_vhost_traffic_status_limit_traffic_by_set_key(ngx_conf_t *cf, ngx_command_t *cmd,
262 | void *conf)
263 | {
264 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf;
265 |
266 | u_char *p;
267 | off_t size;
268 | ngx_str_t *value, s, alpha;
269 | ngx_array_t *limit_traffics;
270 | ngx_http_compile_complex_value_t ccv;
271 | ngx_http_vhost_traffic_status_ctx_t *ctx;
272 | ngx_http_vhost_traffic_status_limit_t *traffic;
273 |
274 | ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module);
275 | if (ctx == NULL) {
276 | return NGX_CONF_ERROR;
277 | }
278 |
279 | value = cf->args->elts;
280 | if (value[1].len == 0) {
281 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty key pattern");
282 | return NGX_CONF_ERROR;
283 | }
284 |
285 | if (value[2].len == 0) {
286 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty value pattern");
287 | return NGX_CONF_ERROR;
288 | }
289 |
290 | if (value[2].len > 5 && ngx_strstrn(value[2].data, "$vts_", 5 - 1)) {
291 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
292 | "limit_traffic_by_set_key() $vts_* is not allowed here");
293 | return NGX_CONF_ERROR;
294 | }
295 |
296 | p = (u_char *) ngx_strchr(value[2].data, ':');
297 | if (p == NULL) {
298 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty size pattern");
299 | return NGX_CONF_ERROR;
300 | }
301 |
302 | s.data = p + 1;
303 | s.len = value[2].data + value[2].len - s.data;
304 |
305 | size = ngx_parse_offset(&s);
306 | if (size == NGX_ERROR) {
307 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
308 | "limit_traffic_by_set_key() invalid limit size \"%V\"", &value[2]);
309 | return NGX_CONF_ERROR;
310 | }
311 |
312 | limit_traffics = (cf->cmd_type == NGX_HTTP_MAIN_CONF)
313 | ? ctx->limit_filter_traffics
314 | : vtscf->limit_filter_traffics;
315 | if (limit_traffics == NULL) {
316 | limit_traffics = ngx_array_create(cf->pool, 1,
317 | sizeof(ngx_http_vhost_traffic_status_limit_t));
318 | if (limit_traffics == NULL) {
319 | return NGX_CONF_ERROR;
320 | }
321 | }
322 |
323 | traffic = ngx_array_push(limit_traffics);
324 | if (traffic == NULL) {
325 | return NGX_CONF_ERROR;
326 | }
327 |
328 | /* set key to be limited */
329 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
330 |
331 | (void) ngx_http_vhost_traffic_status_replace_chrc(&value[1], '@',
332 | NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR);
333 | ngx_str_set(&alpha, "[:alpha:]");
334 | if (ngx_http_vhost_traffic_status_replace_strc(&value[1], &alpha, '@') != NGX_OK) {
335 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
336 | "limit_traffic_by_set_key()::replace_strc() failed");
337 | }
338 |
339 | ccv.cf = cf;
340 | ccv.value = &value[1];
341 | ccv.complex_value = &traffic->key;
342 |
343 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
344 | return NGX_CONF_ERROR;
345 | }
346 |
347 | /* set member to be limited */
348 | value[2].len = p - value[2].data;
349 |
350 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
351 |
352 | ccv.cf = cf;
353 | ccv.value = &value[2];
354 | ccv.complex_value = &traffic->variable;
355 |
356 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
357 | return NGX_CONF_ERROR;
358 | }
359 |
360 | traffic->size = (ngx_atomic_t) size;
361 |
362 | traffic->code = (cf->args->nelts == 4)
363 | ? (ngx_uint_t) ngx_atoi(value[3].data, value[3].len)
364 | : NGX_HTTP_SERVICE_UNAVAILABLE;
365 |
366 | traffic->type = ngx_http_vhost_traffic_status_string_to_group(value[1].data);
367 |
368 | if (cf->cmd_type == NGX_HTTP_MAIN_CONF) {
369 | ctx->limit_filter_traffics = limit_traffics;
370 |
371 | } else {
372 | vtscf->limit_filter_traffics = limit_traffics;
373 | }
374 |
375 | return NGX_CONF_OK;
376 | }
377 |
378 |
379 | ngx_int_t
380 | ngx_http_vhost_traffic_status_limit_traffic_unique(ngx_pool_t *pool, ngx_array_t **keys)
381 | {
382 | uint32_t hash;
383 | u_char *p;
384 | ngx_str_t key;
385 | ngx_uint_t i, n;
386 | ngx_array_t *uniqs, *traffic_keys;
387 | ngx_http_vhost_traffic_status_limit_t *traffic, *traffics;
388 | ngx_http_vhost_traffic_status_filter_uniq_t *traffic_uniqs;
389 |
390 | if (*keys == NULL) {
391 | return NGX_OK;
392 | }
393 |
394 | uniqs = ngx_array_create(pool, 1,
395 | sizeof(ngx_http_vhost_traffic_status_filter_uniq_t));
396 | if (uniqs == NULL) {
397 | return NGX_ERROR;
398 | }
399 |
400 | /* init array */
401 | traffic_keys = NULL;
402 | traffic_uniqs = NULL;
403 |
404 | traffics = (*keys)->elts;
405 | n = (*keys)->nelts;
406 |
407 | for (i = 0; i < n; i++) {
408 | key.len = traffics[i].key.value.len
409 | + traffics[i].variable.value.len;
410 | key.data = ngx_pcalloc(pool, key.len);
411 | if (key.data == NULL) {
412 | return NGX_ERROR;
413 | }
414 |
415 | p = key.data;
416 | p = ngx_cpymem(p, traffics[i].key.value.data,
417 | traffics[i].key.value.len);
418 | ngx_memcpy(p, traffics[i].variable.value.data,
419 | traffics[i].variable.value.len);
420 | hash = ngx_crc32_short(key.data, key.len);
421 |
422 | traffic_uniqs = ngx_array_push(uniqs);
423 | if (traffic_uniqs == NULL) {
424 | return NGX_ERROR;
425 | }
426 |
427 | traffic_uniqs->hash = hash;
428 | traffic_uniqs->index = i;
429 |
430 | if (p != NULL) {
431 | ngx_pfree(pool, key.data);
432 | }
433 | }
434 |
435 | traffic_uniqs = uniqs->elts;
436 | n = uniqs->nelts;
437 |
438 | ngx_qsort(traffic_uniqs, (size_t) n,
439 | sizeof(ngx_http_vhost_traffic_status_filter_uniq_t),
440 | ngx_http_traffic_status_filter_cmp_hashs);
441 |
442 | hash = 0;
443 | for (i = 0; i < n; i++) {
444 | if (traffic_uniqs[i].hash == hash) {
445 | continue;
446 | }
447 |
448 | hash = traffic_uniqs[i].hash;
449 |
450 | if (traffic_keys == NULL) {
451 | traffic_keys = ngx_array_create(pool, 1,
452 | sizeof(ngx_http_vhost_traffic_status_limit_t));
453 | if (traffic_keys == NULL) {
454 | return NGX_ERROR;
455 | }
456 | }
457 |
458 | traffic = ngx_array_push(traffic_keys);
459 | if (traffic == NULL) {
460 | return NGX_ERROR;
461 | }
462 |
463 | ngx_memcpy(traffic, &traffics[traffic_uniqs[i].index],
464 | sizeof(ngx_http_vhost_traffic_status_limit_t));
465 |
466 | }
467 |
468 | if ((*keys)->nelts != traffic_keys->nelts) {
469 | *keys = traffic_keys;
470 | }
471 |
472 | return NGX_OK;
473 | }
474 |
475 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
476 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_limit.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_LIMIT_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_LIMIT_H_INCLUDED_
9 |
10 |
11 | typedef struct {
12 | ngx_http_complex_value_t key;
13 | ngx_http_complex_value_t variable;
14 | ngx_atomic_t size;
15 | ngx_uint_t code;
16 | unsigned type; /* unsigned type:5 */
17 | } ngx_http_vhost_traffic_status_limit_t;
18 |
19 |
20 | ngx_int_t ngx_http_vhost_traffic_status_limit_handler(ngx_http_request_t *r);
21 | ngx_int_t ngx_http_vhost_traffic_status_limit_handler_traffic(ngx_http_request_t *r,
22 | ngx_array_t *traffics);
23 |
24 | ngx_int_t ngx_http_vhost_traffic_status_limit_traffic_unique(
25 | ngx_pool_t *pool, ngx_array_t **keys);
26 | char *ngx_http_vhost_traffic_status_limit_traffic(ngx_conf_t *cf,
27 | ngx_command_t *cmd, void *conf);
28 | char *ngx_http_vhost_traffic_status_limit_traffic_by_set_key(ngx_conf_t *cf,
29 | ngx_command_t *cmd, void *conf);
30 |
31 |
32 | #endif /* _NGX_HTTP_VTS_LIMIT_H_INCLUDED_ */
33 |
34 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
35 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_node.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_NODE_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_NODE_H_INCLUDED_
9 |
10 |
11 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN 64
12 | #define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN 32
13 |
14 | typedef struct {
15 | ngx_msec_t time;
16 | ngx_msec_int_t msec;
17 | } ngx_http_vhost_traffic_status_node_time_t;
18 |
19 |
20 | typedef struct {
21 | ngx_http_vhost_traffic_status_node_time_t times[NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN];
22 | ngx_int_t front;
23 | ngx_int_t rear;
24 | ngx_int_t len;
25 | } ngx_http_vhost_traffic_status_node_time_queue_t;
26 |
27 |
28 | typedef struct {
29 | ngx_msec_int_t msec;
30 | ngx_atomic_t counter;
31 | } ngx_http_vhost_traffic_status_node_histogram_t;
32 |
33 |
34 | typedef struct {
35 | ngx_http_vhost_traffic_status_node_histogram_t buckets[NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN];
36 | ngx_int_t len;
37 | } ngx_http_vhost_traffic_status_node_histogram_bucket_t;
38 |
39 |
40 | typedef struct {
41 | /* unsigned type:5 */
42 | unsigned type;
43 | ngx_atomic_t response_time_counter;
44 | ngx_msec_t response_time;
45 | ngx_http_vhost_traffic_status_node_time_queue_t response_times;
46 | ngx_http_vhost_traffic_status_node_histogram_bucket_t response_buckets;
47 | } ngx_http_vhost_traffic_status_node_upstream_t;
48 |
49 |
50 | typedef struct {
51 | u_char color;
52 | ngx_atomic_t stat_request_counter;
53 | ngx_atomic_t stat_in_bytes;
54 | ngx_atomic_t stat_out_bytes;
55 | ngx_atomic_t stat_1xx_counter;
56 | ngx_atomic_t stat_2xx_counter;
57 | ngx_atomic_t stat_3xx_counter;
58 | ngx_atomic_t stat_4xx_counter;
59 | ngx_atomic_t stat_5xx_counter;
60 | uint stat_status_code_length;
61 | ngx_atomic_t *stat_status_code_counter;
62 |
63 | ngx_atomic_t stat_request_time_counter;
64 | ngx_msec_t stat_request_time;
65 | ngx_http_vhost_traffic_status_node_time_queue_t stat_request_times;
66 | ngx_http_vhost_traffic_status_node_histogram_bucket_t stat_request_buckets;
67 |
68 | /* deals with the overflow of variables */
69 | ngx_atomic_t stat_request_counter_oc;
70 | ngx_atomic_t stat_in_bytes_oc;
71 | ngx_atomic_t stat_out_bytes_oc;
72 | ngx_atomic_t stat_1xx_counter_oc;
73 | ngx_atomic_t stat_2xx_counter_oc;
74 | ngx_atomic_t stat_3xx_counter_oc;
75 | ngx_atomic_t stat_4xx_counter_oc;
76 | ngx_atomic_t stat_5xx_counter_oc;
77 | ngx_atomic_t stat_request_time_counter_oc;
78 | ngx_atomic_t stat_response_time_counter_oc;
79 |
80 | #if (NGX_HTTP_CACHE)
81 | ngx_atomic_t stat_cache_max_size;
82 | ngx_atomic_t stat_cache_used_size;
83 | ngx_atomic_t stat_cache_miss_counter;
84 | ngx_atomic_t stat_cache_bypass_counter;
85 | ngx_atomic_t stat_cache_expired_counter;
86 | ngx_atomic_t stat_cache_stale_counter;
87 | ngx_atomic_t stat_cache_updating_counter;
88 | ngx_atomic_t stat_cache_revalidated_counter;
89 | ngx_atomic_t stat_cache_hit_counter;
90 | ngx_atomic_t stat_cache_scarce_counter;
91 |
92 | /* deals with the overflow of variables */
93 | ngx_atomic_t stat_cache_miss_counter_oc;
94 | ngx_atomic_t stat_cache_bypass_counter_oc;
95 | ngx_atomic_t stat_cache_expired_counter_oc;
96 | ngx_atomic_t stat_cache_stale_counter_oc;
97 | ngx_atomic_t stat_cache_updating_counter_oc;
98 | ngx_atomic_t stat_cache_revalidated_counter_oc;
99 | ngx_atomic_t stat_cache_hit_counter_oc;
100 | ngx_atomic_t stat_cache_scarce_counter_oc;
101 | #endif
102 |
103 | ngx_http_vhost_traffic_status_node_upstream_t stat_upstream;
104 | size_t len;
105 | ngx_uint_t ignore_status;
106 | u_char data[1];
107 | } ngx_http_vhost_traffic_status_node_t;
108 |
109 |
110 | ngx_int_t ngx_http_vhost_traffic_status_node_generate_key(ngx_pool_t *pool,
111 | ngx_str_t *buf, ngx_str_t *dst, unsigned type);
112 | ngx_int_t ngx_http_vhost_traffic_status_node_position_key(ngx_str_t *buf,
113 | size_t pos);
114 |
115 | ngx_rbtree_node_t *ngx_http_vhost_traffic_status_node_lookup(
116 | ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash);
117 | void ngx_http_vhost_traffic_status_node_zero(
118 | ngx_http_vhost_traffic_status_node_t *vtsn);
119 | void ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r,
120 | ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot);
121 | void ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r,
122 | ngx_http_vhost_traffic_status_node_t *vtsn, ngx_int_t status_code_slot);
123 | void ngx_http_vhost_traffic_status_node_update(ngx_http_request_t *r,
124 | ngx_http_vhost_traffic_status_node_t *vtsn, ngx_msec_int_t ms, ngx_int_t status_code_slot);
125 |
126 | void ngx_http_vhost_traffic_status_node_time_queue_zero(
127 | ngx_http_vhost_traffic_status_node_time_queue_t *q);
128 | void ngx_http_vhost_traffic_status_node_time_queue_init(
129 | ngx_http_vhost_traffic_status_node_time_queue_t *q);
130 | void ngx_http_vhost_traffic_status_node_time_queue_insert(
131 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
132 | ngx_msec_int_t x);
133 | ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_push(
134 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
135 | ngx_msec_int_t x);
136 | ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_pop(
137 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
138 | ngx_http_vhost_traffic_status_node_time_t *x);
139 | ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_rear(
140 | ngx_http_vhost_traffic_status_node_time_queue_t *q);
141 |
142 | ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_average(
143 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
144 | ngx_int_t method, ngx_msec_t period);
145 | ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_amm(
146 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
147 | ngx_msec_t period);
148 | ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_wma(
149 | ngx_http_vhost_traffic_status_node_time_queue_t *q,
150 | ngx_msec_t period);
151 | void ngx_http_vhost_traffic_status_node_time_queue_merge(
152 | ngx_http_vhost_traffic_status_node_time_queue_t *a,
153 | ngx_http_vhost_traffic_status_node_time_queue_t *b,
154 | ngx_msec_t period);
155 | void ngx_http_vhost_traffic_status_status_code_merge(ngx_atomic_t *dst, ngx_atomic_t *src, ngx_uint_t n);
156 |
157 | void ngx_http_vhost_traffic_status_node_histogram_bucket_init(
158 | ngx_http_request_t *r,
159 | ngx_http_vhost_traffic_status_node_histogram_bucket_t *b);
160 | void ngx_http_vhost_traffic_status_node_histogram_observe(
161 | ngx_http_vhost_traffic_status_node_histogram_bucket_t *b,
162 | ngx_msec_int_t x);
163 |
164 | void ngx_http_vhost_traffic_status_find_name(ngx_http_request_t *r,
165 | ngx_str_t *buf);
166 | ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_node(ngx_http_request_t *r,
167 | ngx_str_t *key, unsigned type, uint32_t key_hash);
168 |
169 | ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru(ngx_http_request_t *r);
170 | ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru_node(ngx_http_request_t *r,
171 | ngx_rbtree_node_t *a, ngx_rbtree_node_t *b);
172 | ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru_node_cmp(ngx_http_request_t *r,
173 | ngx_rbtree_node_t *a, ngx_rbtree_node_t *b);
174 |
175 | ngx_int_t ngx_http_vhost_traffic_status_node_member_cmp(ngx_str_t *member, const char *name);
176 | ngx_atomic_uint_t ngx_http_vhost_traffic_status_node_member(
177 | ngx_http_vhost_traffic_status_node_t *vtsn,
178 | ngx_str_t *member);
179 |
180 |
181 | #endif /* _NGX_HTTP_VTS_NODE_H_INCLUDED_ */
182 |
183 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
184 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_set.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_SET_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_SET_H_INCLUDED_
9 |
10 |
11 | typedef struct {
12 | ngx_int_t index;
13 | ngx_http_complex_value_t value;
14 | ngx_http_set_variable_pt set_handler;
15 | } ngx_http_vhost_traffic_status_filter_variable_t;
16 |
17 |
18 | ngx_int_t ngx_http_vhost_traffic_status_set_handler(ngx_http_request_t *r);
19 | char *ngx_http_vhost_traffic_status_set_by_filter(ngx_conf_t *cf,
20 | ngx_command_t *cmd, void *conf);
21 |
22 |
23 | #endif /* _NGX_HTTP_VTS_SET_H_INCLUDED_ */
24 |
25 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
26 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_shm.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_SHM_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_SHM_H_INCLUDED_
9 |
10 |
11 | typedef struct {
12 | ngx_str_t *name;
13 | ngx_uint_t max_size;
14 | ngx_uint_t used_size;
15 | ngx_uint_t used_node;
16 |
17 | ngx_uint_t filter_used_size;
18 | ngx_uint_t filter_used_node;
19 | } ngx_http_vhost_traffic_status_shm_info_t;
20 |
21 |
22 | ngx_int_t ngx_http_vhost_traffic_status_shm_add_server(ngx_http_request_t *r);
23 | ngx_int_t ngx_http_vhost_traffic_status_shm_add_filter(ngx_http_request_t *r);
24 | ngx_int_t ngx_http_vhost_traffic_status_shm_add_upstream(ngx_http_request_t *r);
25 | ngx_uint_t ngx_http_vhost_traffic_status_find_status_code_slot(ngx_uint_t status, ngx_array_t *status_codes);
26 |
27 | #if (NGX_HTTP_CACHE)
28 | ngx_int_t ngx_http_vhost_traffic_status_shm_add_cache(ngx_http_request_t *r);
29 | #endif
30 |
31 | void ngx_http_vhost_traffic_status_shm_info_node(ngx_http_request_t *r,
32 | ngx_http_vhost_traffic_status_shm_info_t *shm_info, ngx_rbtree_node_t *node);
33 | void ngx_http_vhost_traffic_status_shm_info(ngx_http_request_t *r,
34 | ngx_http_vhost_traffic_status_shm_info_t *shm_info);
35 |
36 |
37 | #endif /* _NGX_HTTP_VTS_SHM_H_INCLUDED_ */
38 |
39 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
40 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_string.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 | #include
7 |
8 | #include
9 | #include
10 |
11 | #include "ngx_http_vhost_traffic_status_string.h"
12 |
13 |
14 | #if !defined(nginx_version) || nginx_version < 1007009
15 |
16 | /* from src/core/ngx_string.c in v1.7.9 */
17 | uintptr_t
18 | ngx_http_vhost_traffic_status_escape_json(u_char *dst, u_char *src, size_t size)
19 | {
20 | u_char ch;
21 | ngx_uint_t len;
22 |
23 | if (dst == NULL) {
24 | len = 0;
25 |
26 | while (size) {
27 | ch = *src++;
28 |
29 | if (ch == '\\' || ch == '"') {
30 | len++;
31 |
32 | } else if (ch <= 0x1f) {
33 | len += sizeof("\\u001F") - 2;
34 | }
35 |
36 | size--;
37 | }
38 |
39 | return (uintptr_t) len;
40 | }
41 |
42 | while (size) {
43 | ch = *src++;
44 |
45 | if (ch > 0x1f) {
46 |
47 | if (ch == '\\' || ch == '"') {
48 | *dst++ = '\\';
49 | }
50 |
51 | *dst++ = ch;
52 |
53 | } else {
54 | *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
55 | *dst++ = '0' + (ch >> 4);
56 |
57 | ch &= 0xf;
58 |
59 | *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
60 | }
61 |
62 | size--;
63 | }
64 |
65 | return (uintptr_t) dst;
66 | }
67 |
68 | #endif
69 |
70 |
71 | ngx_int_t
72 | ngx_http_vhost_traffic_status_escape_json_pool(ngx_pool_t *pool,
73 | ngx_str_t *buf, ngx_str_t *dst)
74 | {
75 | u_char *p;
76 |
77 | buf->len = dst->len * 6;
78 | buf->data = ngx_pcalloc(pool, buf->len);
79 | if (buf->data == NULL) {
80 | *buf = *dst;
81 | return NGX_ERROR;
82 | }
83 |
84 | p = buf->data;
85 |
86 | #if !defined(nginx_version) || nginx_version < 1007009
87 | p = (u_char *) ngx_http_vhost_traffic_status_escape_json(p, dst->data, dst->len);
88 | #else
89 | p = (u_char *) ngx_escape_json(p, dst->data, dst->len);
90 | #endif
91 |
92 | buf->len = ngx_strlen(buf->data);
93 |
94 | return NGX_OK;
95 | }
96 |
97 |
98 | ngx_int_t
99 | ngx_http_vhost_traffic_status_copy_str(ngx_pool_t *pool,
100 | ngx_str_t *buf, ngx_str_t *dst)
101 | {
102 | u_char *p;
103 |
104 | buf->len = dst->len;
105 | buf->data = ngx_pcalloc(pool, dst->len + 1); /* 1 byte for terminating '\0' */
106 | if (buf->data == NULL) {
107 | return NGX_ERROR;
108 | }
109 |
110 | p = buf->data;
111 |
112 | ngx_memcpy(p, dst->data, dst->len);
113 |
114 | return NGX_OK;
115 | }
116 |
117 |
118 | ngx_int_t
119 | ngx_http_vhost_traffic_status_replace_chrc(ngx_str_t *buf,
120 | u_char in, u_char to)
121 | {
122 | size_t len;
123 | u_char *p;
124 |
125 | p = buf->data;
126 |
127 | len = buf->len;
128 |
129 | while(len--) {
130 | if (*p == in) {
131 | *p = to;
132 | }
133 | p++;
134 | }
135 |
136 | return NGX_OK;
137 | }
138 |
139 |
140 | ngx_int_t
141 | ngx_http_vhost_traffic_status_replace_strc(ngx_str_t *buf,
142 | ngx_str_t *dst, u_char c)
143 | {
144 | size_t n, len;
145 | u_char *p, *o;
146 | p = o = buf->data;
147 | n = 0;
148 |
149 | /* we need the buf's last '\0' for ngx_strstrn() */
150 | if (*(buf->data + buf->len) != 0) {
151 | return NGX_ERROR;
152 | }
153 |
154 | while ((p = ngx_strstrn(p, (char *) dst->data, dst->len - 1)) != NULL) {
155 | n++;
156 | len = buf->len - (p - o) - (n * dst->len) + n - 1;
157 | *p++ = c;
158 | ngx_memmove(p, p + dst->len - 1, len);
159 | }
160 |
161 | if (n > 0) {
162 | buf->len = buf->len - (n * dst->len) + n;
163 | }
164 | *(buf->data + buf->len) = '\0';
165 |
166 | return NGX_OK;
167 | }
168 |
169 |
170 | ngx_int_t
171 | ngx_http_vhost_traffic_status_escape_prometheus(ngx_pool_t *pool, ngx_str_t *buf, u_char *p, size_t n)
172 | {
173 | u_char c, *pa, *pb, *last, *char_end;
174 | size_t size;
175 | u_char HEX_MAP[] = "0123456789ABCDEF";
176 |
177 | last = p + n;
178 | pa = p;
179 | size = 0;
180 |
181 | /* Find the first character that needs to be escaped */
182 | while (pa < last) {
183 | if (isascii(*pa)) {
184 | if (*pa == '"' || *pa == '\\' || *pa == '\n') {
185 | break;
186 | } else {
187 | pa++;
188 | }
189 | } else {
190 | char_end = pa;
191 | if (*pa >= 0xf8 || ngx_utf8_decode(&char_end, last - pa) > 0x10ffff) {
192 | break;
193 | } else {
194 | pa = char_end;
195 | }
196 | }
197 | }
198 |
199 | if (pa == last) {
200 | // no escapes required - return the original string
201 | buf->data = p;
202 | buf->len = n;
203 | return NGX_OK;
204 | }
205 |
206 | size = pa - p;
207 |
208 | /* Allocate enough space for the unescaped prefix and worst case for remainder */
209 | buf->data = ngx_pcalloc(pool, size + (n - size) * 5);
210 | if (buf->data == NULL) {
211 | /*
212 | Return the unescaped string up to the first special character
213 | in case the caller does not handle the error.
214 | */
215 | buf->data = p;
216 | buf->len = size;
217 | return NGX_ERROR;
218 | }
219 |
220 | /* Copy `size` unescaped characters to start of destination. */
221 | pb = ngx_copy(buf->data, p, size);
222 |
223 | /* Individually copy remaining characters to destination, escaping as necessary */
224 | while (pa < last) {
225 | if (isascii(*pa)) {
226 | if (*pa == '"' || *pa == '\\') {
227 | *pb++ = '\\';
228 | *pb++ = *pa++;
229 | size += 2;
230 | } else if (*pa == '\n') {
231 | *pb++ = '\\';
232 | *pb++ = 'n';
233 | pa++;
234 | size += 2;
235 | } else {
236 | *pb++ = *pa++;
237 | size++;
238 | }
239 | } else {
240 | char_end = pa;
241 | if (*pa >= 0xf8 || ngx_utf8_decode(&char_end, last - pa) > 0x10ffff) {
242 | /* invalid UTF-8 - escape single char to allow resynchronization */
243 | c = *pa++;
244 | /* two slashes are required to be valid encoding for prometheus*/
245 | *pb++ = '\\';
246 | *pb++ = '\\';
247 | *pb++ = 'x';
248 | *pb++ = HEX_MAP[c >> 4];
249 | *pb++ = HEX_MAP[c & 0x0f];
250 | size += 5;
251 | } else {
252 | while (pa < char_end) {
253 | *pb++ = *pa++;
254 | size++;
255 | }
256 | }
257 | }
258 | }
259 |
260 | buf->len = size;
261 | return NGX_OK;
262 | }
263 |
264 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
265 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_string.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_STRING_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_STRING_H_INCLUDED_
9 |
10 |
11 | #if !defined(nginx_version) || nginx_version < 1007009
12 | uintptr_t ngx_http_vhost_traffic_status_escape_json(u_char *dst, u_char *src, size_t size);
13 | #endif
14 | ngx_int_t ngx_http_vhost_traffic_status_escape_json_pool(ngx_pool_t *pool,
15 | ngx_str_t *buf, ngx_str_t *dst);
16 | ngx_int_t ngx_http_vhost_traffic_status_copy_str(ngx_pool_t *pool,
17 | ngx_str_t *buf, ngx_str_t *dst);
18 | ngx_int_t ngx_http_vhost_traffic_status_replace_chrc(ngx_str_t *buf,
19 | u_char in, u_char to);
20 | ngx_int_t ngx_http_vhost_traffic_status_replace_strc(ngx_str_t *buf,
21 | ngx_str_t *dst, u_char c);
22 | ngx_int_t ngx_http_vhost_traffic_status_escape_prometheus(ngx_pool_t *pool, ngx_str_t *buf,
23 | u_char *p, size_t n);
24 |
25 | #endif /* _NGX_HTTP_VTS_STRING_H_INCLUDED_ */
26 |
27 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
28 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_variables.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #include "ngx_http_vhost_traffic_status_module.h"
8 | #include "ngx_http_vhost_traffic_status_variables.h"
9 |
10 |
11 | static ngx_http_variable_t ngx_http_vhost_traffic_status_vars[] = {
12 |
13 | { ngx_string("vts_request_counter"), NULL,
14 | ngx_http_vhost_traffic_status_node_variable,
15 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_counter),
16 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
17 |
18 | { ngx_string("vts_in_bytes"), NULL,
19 | ngx_http_vhost_traffic_status_node_variable,
20 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_in_bytes),
21 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
22 |
23 | { ngx_string("vts_out_bytes"), NULL,
24 | ngx_http_vhost_traffic_status_node_variable,
25 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_out_bytes),
26 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
27 |
28 | { ngx_string("vts_1xx_counter"), NULL,
29 | ngx_http_vhost_traffic_status_node_variable,
30 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_1xx_counter),
31 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
32 |
33 | { ngx_string("vts_2xx_counter"), NULL,
34 | ngx_http_vhost_traffic_status_node_variable,
35 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_2xx_counter),
36 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
37 |
38 | { ngx_string("vts_3xx_counter"), NULL,
39 | ngx_http_vhost_traffic_status_node_variable,
40 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_3xx_counter),
41 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
42 |
43 | { ngx_string("vts_4xx_counter"), NULL,
44 | ngx_http_vhost_traffic_status_node_variable,
45 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_4xx_counter),
46 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
47 |
48 | { ngx_string("vts_5xx_counter"), NULL,
49 | ngx_http_vhost_traffic_status_node_variable,
50 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_5xx_counter),
51 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
52 |
53 | { ngx_string("vts_request_time_counter"), NULL,
54 | ngx_http_vhost_traffic_status_node_variable,
55 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_time_counter),
56 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
57 |
58 | { ngx_string("vts_request_time"), NULL,
59 | ngx_http_vhost_traffic_status_node_variable,
60 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_time),
61 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
62 |
63 | #if (NGX_HTTP_CACHE)
64 | { ngx_string("vts_cache_miss_counter"), NULL,
65 | ngx_http_vhost_traffic_status_node_variable,
66 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_miss_counter),
67 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
68 |
69 | { ngx_string("vts_cache_bypass_counter"), NULL,
70 | ngx_http_vhost_traffic_status_node_variable,
71 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_bypass_counter),
72 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
73 |
74 | { ngx_string("vts_cache_expired_counter"), NULL,
75 | ngx_http_vhost_traffic_status_node_variable,
76 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_expired_counter),
77 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
78 |
79 | { ngx_string("vts_cache_stale_counter"), NULL,
80 | ngx_http_vhost_traffic_status_node_variable,
81 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_stale_counter),
82 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
83 |
84 | { ngx_string("vts_cache_updating_counter"), NULL,
85 | ngx_http_vhost_traffic_status_node_variable,
86 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_updating_counter),
87 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
88 |
89 | { ngx_string("vts_cache_revalidated_counter"), NULL,
90 | ngx_http_vhost_traffic_status_node_variable,
91 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_revalidated_counter),
92 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
93 |
94 | { ngx_string("vts_cache_hit_counter"), NULL,
95 | ngx_http_vhost_traffic_status_node_variable,
96 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_hit_counter),
97 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
98 |
99 | { ngx_string("vts_cache_scarce_counter"), NULL,
100 | ngx_http_vhost_traffic_status_node_variable,
101 | offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_scarce_counter),
102 | NGX_HTTP_VAR_NOCACHEABLE, 0 },
103 | #endif
104 |
105 | { ngx_null_string, NULL, NULL, 0, 0, 0 }
106 | };
107 |
108 |
109 | ngx_int_t
110 | ngx_http_vhost_traffic_status_node_variable(ngx_http_request_t *r,
111 | ngx_http_variable_value_t *v, uintptr_t data)
112 | {
113 | u_char *p;
114 | unsigned type;
115 | ngx_int_t rc;
116 | ngx_str_t key, dst;
117 | ngx_slab_pool_t *shpool;
118 | ngx_rbtree_node_t *node;
119 | ngx_http_vhost_traffic_status_node_t *vtsn;
120 | ngx_http_vhost_traffic_status_loc_conf_t *vtscf;
121 |
122 | vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module);
123 |
124 | ngx_http_vhost_traffic_status_find_name(r, &dst);
125 |
126 | type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO;
127 |
128 | rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type);
129 | if (rc != NGX_OK) {
130 | return NGX_ERROR;
131 | }
132 |
133 | if (key.len == 0) {
134 | return NGX_ERROR;
135 | }
136 |
137 | shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr;
138 |
139 | ngx_shmtx_lock(&shpool->mutex);
140 |
141 | node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0);
142 |
143 | if (node == NULL) {
144 | goto not_found;
145 | }
146 |
147 | p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN);
148 | if (p == NULL) {
149 | goto not_found;
150 | }
151 |
152 | vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
153 |
154 | v->len = ngx_sprintf(p, "%uA", *((ngx_atomic_t *) ((char *) vtsn + data))) - p;
155 | v->valid = 1;
156 | v->no_cacheable = 0;
157 | v->not_found = 0;
158 | v->data = p;
159 |
160 | goto done;
161 |
162 | not_found:
163 |
164 | v->not_found = 1;
165 |
166 | done:
167 |
168 | vtscf->node_caches[type] = node;
169 |
170 | ngx_shmtx_unlock(&shpool->mutex);
171 |
172 | return NGX_OK;
173 | }
174 |
175 |
176 | ngx_int_t
177 | ngx_http_vhost_traffic_status_add_variables(ngx_conf_t *cf)
178 | {
179 | ngx_http_variable_t *var, *v;
180 |
181 | for (v = ngx_http_vhost_traffic_status_vars; v->name.len; v++) {
182 | var = ngx_http_add_variable(cf, &v->name, v->flags);
183 | if (var == NULL) {
184 | return NGX_ERROR;
185 | }
186 |
187 | var->get_handler = v->get_handler;
188 | var->data = v->data;
189 | }
190 |
191 | return NGX_OK;
192 | }
193 |
194 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
195 |
--------------------------------------------------------------------------------
/src/ngx_http_vhost_traffic_status_variables.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) YoungJoo Kim (vozlt)
4 | */
5 |
6 |
7 | #ifndef _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_
8 | #define _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_
9 |
10 |
11 | ngx_int_t ngx_http_vhost_traffic_status_node_variable(ngx_http_request_t *r,
12 | ngx_http_variable_value_t *v, uintptr_t data);
13 | ngx_int_t ngx_http_vhost_traffic_status_add_variables(ngx_conf_t *cf);
14 |
15 |
16 | #endif /* _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_ */
17 |
18 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
19 |
--------------------------------------------------------------------------------
/t/000.display_html.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each(2) * blocks() * 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/format/html
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format html;
18 | }
19 | --- request
20 | GET /status/format/html
21 | --- response_headers_like
22 | Content-Type: text/html
23 |
24 |
25 |
26 | === TEST 2: /status
27 | --- http_config
28 | vhost_traffic_status_zone;
29 | --- config
30 | location /status {
31 | vhost_traffic_status_display;
32 | vhost_traffic_status_display_format html;
33 | }
34 | --- request
35 | GET /status
36 | --- response_headers_like
37 | Content-Type: text/html
38 |
--------------------------------------------------------------------------------
/t/001.display_json.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each(2) * blocks() * 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/format/json
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | }
19 | --- request
20 | GET /status/format/json
21 | --- response_headers_like
22 | Content-Type: application/json
23 |
24 |
25 |
26 | === TEST 2: /status
27 | --- http_config
28 | vhost_traffic_status_zone;
29 | --- config
30 | location /status {
31 | vhost_traffic_status_display;
32 | vhost_traffic_status_display_format json;
33 | }
34 | --- request
35 | GET /status
36 | --- response_headers_like
37 | Content-Type: application/json
38 |
--------------------------------------------------------------------------------
/t/002.check_json_syntax.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | add_response_body_check(
6 | sub {
7 | my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_;
8 | system("echo '$body' | python -m json.tool > /dev/null") == 0 or
9 | bail_out "JSON Syntax error($body)";
10 | }
11 | );
12 |
13 | plan tests => repeat_each() * blocks() * 24;
14 | no_shuffle();
15 | run_tests();
16 |
17 | __DATA__
18 |
19 | === TEST 1: check_json_syntax
20 | --- http_config
21 | vhost_traffic_status_zone;
22 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
23 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
24 | upstream backend {
25 | server 127.0.0.1;
26 | }
27 | server {
28 | server_name _;
29 | vhost_traffic_status_filter_by_host on;
30 | }
31 | --- config
32 | location /status {
33 | vhost_traffic_status_display;
34 | vhost_traffic_status_display_format json;
35 | access_log off;
36 | }
37 | location /one {
38 | proxy_set_header Host one.example.org;
39 | proxy_pass http://backend;
40 | }
41 | location /two {
42 | proxy_set_header Host two.example.org;
43 | proxy_pass http://backend;
44 | }
45 | location ~ ^/storage/(.+)/.*$ {
46 | set $volume $1;
47 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
48 | }
49 | location /alone {
50 | proxy_pass http://localhost:1981;
51 | }
52 | location /cache_one {
53 | proxy_cache cache_one;
54 | proxy_cache_valid 200 10s;
55 | proxy_set_header Host backend;
56 | proxy_pass http://backend;
57 | }
58 | location /cache_two {
59 | proxy_cache cache_two;
60 | proxy_cache_valid 200 10s;
61 | proxy_set_header Host backend;
62 | proxy_pass http://backend;
63 | }
64 | --- tcp_listen: 1981
65 | --- tcp_reply eval
66 | "HTTP/1.1 200 OK\r\n\r\n{\"upstream\@alone\":\"OK\"}"
67 | --- user_files eval
68 | [
69 | ['one/file.txt' => '{"one.example.org":"OK"}'],
70 | ['two/file.txt' => '{"two.example.org":"OK"}'],
71 | ['storage/vol0/file.txt' => '{"vol0":"OK"}'],
72 | ['storage/vol1/file.txt' => '{"vol1":"OK"}'],
73 | ['cache_one/file.txt' => '{"cache_one":"OK"}'],
74 | ['cache_two/file.txt' => '{"cache_two":"OK"}']
75 | ]
76 | --- request eval
77 | [
78 | 'GET /status/format/json',
79 | 'GET /one/file.txt',
80 | 'GET /two/file.txt',
81 | 'GET /status/format/json',
82 | 'GET /storage/vol0/file.txt',
83 | 'GET /storage/vol1/file.txt',
84 | 'GET /status/format/json',
85 | 'GET /alone/file.txt',
86 | 'GET /status/format/json',
87 | 'GET /cache_one/file.txt',
88 | 'GET /cache_two/file.txt',
89 | 'GET /status/format/json'
90 | ]
91 | --- response_body_like eval
92 | [
93 | 'nginxVersion',
94 | 'OK',
95 | 'OK',
96 | '(one|two).example.org',
97 | 'OK',
98 | 'OK',
99 | 'filterZones.*(vol0|vol1)',
100 | 'OK',
101 | '::nogroups',
102 | 'OK',
103 | 'OK',
104 | 'cacheZone'
105 | ]
106 |
--------------------------------------------------------------------------------
/t/003.filter_by_host.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 8;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: vhost_traffic_status_filter_by_host on
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | upstream backend {
15 | server 127.0.0.1;
16 | }
17 | server {
18 | server_name _;
19 | vhost_traffic_status_filter_by_host on;
20 | }
21 | --- config
22 | location /status {
23 | vhost_traffic_status_display;
24 | vhost_traffic_status_display_format json;
25 | access_log off;
26 | }
27 | location /one {
28 | proxy_set_header Host one.example.org;
29 | proxy_pass http://backend;
30 | }
31 | location /two {
32 | proxy_set_header Host two.example.org;
33 | proxy_pass http://backend;
34 | }
35 | --- user_files eval
36 | [
37 | ['one/file.txt' => 'one.example.org:OK'],
38 | ['two/file.txt' => 'two.example.org:OK']
39 | ]
40 | --- request eval
41 | [
42 | 'GET /one/file.txt',
43 | 'GET /two/file.txt',
44 | 'GET /status/control?cmd=status&group=server&zone=one.example.org',
45 | 'GET /status/control?cmd=status&group=server&zone=two.example.org'
46 | ]
47 | --- response_body_like eval
48 | [
49 | 'OK',
50 | 'OK',
51 | 'one.example.org',
52 | 'two.example.org'
53 | ]
54 |
55 |
56 |
57 | === TEST 2: vhost_traffic_status_filter off
58 | --- http_config
59 | vhost_traffic_status_zone;
60 | vhost_traffic_status_filter off;
61 | upstream backend {
62 | server 127.0.0.1;
63 | }
64 | server {
65 | server_name _;
66 | vhost_traffic_status_filter_by_host on;
67 | }
68 | --- config
69 | location /status {
70 | vhost_traffic_status_display;
71 | vhost_traffic_status_display_format json;
72 | access_log off;
73 | }
74 | location /one {
75 | proxy_set_header Host one.example.org;
76 | proxy_pass http://backend;
77 | }
78 | location /two {
79 | proxy_set_header Host two.example.org;
80 | proxy_pass http://backend;
81 | }
82 | --- user_files eval
83 | [
84 | ['one/file.txt' => 'one.example.org:OK'],
85 | ['two/file.txt' => 'two.example.org:OK']
86 | ]
87 | --- request eval
88 | [
89 | 'GET /one/file.txt',
90 | 'GET /two/file.txt',
91 | 'GET /status/control?cmd=status&group=server&zone=one.example.org',
92 | 'GET /status/control?cmd=status&group=server&zone=two.example.org'
93 | ]
94 | --- response_body_like eval
95 | [
96 | 'OK',
97 | 'OK',
98 | '{}',
99 | '{}'
100 | ]
101 |
--------------------------------------------------------------------------------
/t/004.filter_by_set_key.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 12;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: filter_by_set_key
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | location ~ ^/storage/(.+)/.*$ {
21 | set $volume $1;
22 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
23 | }
24 | --- user_files eval
25 | [
26 | ['storage/vol0/file.txt' => 'vol0:OK'],
27 | ['storage/vol1/file.txt' => 'vol1:OK'],
28 | ['storage/vol2/file.txt' => 'vol2:OK']
29 | ]
30 | --- request eval
31 | [
32 | 'GET /storage/vol0/file.txt',
33 | 'GET /storage/vol1/file.txt',
34 | 'GET /storage/vol2/file.txt',
35 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0',
36 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1',
37 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2',
38 | ]
39 | --- response_body_like eval
40 | [
41 | 'OK',
42 | 'OK',
43 | 'OK',
44 | 'vol0',
45 | 'vol1',
46 | 'vol2'
47 | ]
48 |
--------------------------------------------------------------------------------
/t/005.filter_check_duplicate.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 12;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: filter_check_duplicate on
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | location ~ ^/storage/(.+)/.*$ {
21 | set $volume $1;
22 | vhost_traffic_status_filter_check_duplicate on;
23 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
24 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
25 | }
26 | --- user_files eval
27 | [
28 | ['storage/vol0/file.txt' => 'vol0:OK'],
29 | ['storage/vol1/file.txt' => 'vol1:OK'],
30 | ['storage/vol2/file.txt' => 'vol2:OK']
31 | ]
32 | --- request eval
33 | [
34 | 'GET /storage/vol0/file.txt',
35 | 'GET /storage/vol1/file.txt',
36 | 'GET /storage/vol2/file.txt',
37 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0',
38 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1',
39 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2',
40 | ]
41 | --- response_body_like eval
42 | [
43 | 'OK',
44 | 'OK',
45 | 'OK',
46 | 'vol0.*"requestCounter":1',
47 | 'vol1.*"requestCounter":1',
48 | 'vol2.*"requestCounter":1'
49 | ]
50 |
51 |
52 |
53 | === TEST 2: filter_check_duplicate off
54 | --- http_config
55 | vhost_traffic_status_zone;
56 | --- config
57 | location /status {
58 | vhost_traffic_status_display;
59 | vhost_traffic_status_display_format json;
60 | access_log off;
61 | }
62 | location ~ ^/storage/(.+)/.*$ {
63 | set $volume $1;
64 | vhost_traffic_status_filter_check_duplicate off;
65 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
66 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
67 | }
68 | --- user_files eval
69 | [
70 | ['storage/vol0/file.txt' => 'vol0:OK'],
71 | ['storage/vol1/file.txt' => 'vol1:OK'],
72 | ['storage/vol2/file.txt' => 'vol2:OK']
73 | ]
74 | --- request eval
75 | [
76 | 'GET /storage/vol0/file.txt',
77 | 'GET /storage/vol1/file.txt',
78 | 'GET /storage/vol2/file.txt',
79 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0',
80 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1',
81 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2',
82 | ]
83 | --- response_body_like eval
84 | [
85 | 'OK',
86 | 'OK',
87 | 'OK',
88 | 'vol0.*"requestCounter":2',
89 | 'vol1.*"requestCounter":2',
90 | 'vol2.*"requestCounter":2'
91 | ]
92 |
--------------------------------------------------------------------------------
/t/006.control_status_fully.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=status&group=*
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | location ~ ^/storage/(.+)/.*$ {
21 | set $volume $1;
22 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
23 | }
24 | --- user_files eval
25 | [
26 | ['storage/vol0/file.txt' => 'vol0:OK']
27 | ]
28 | --- request eval
29 | [
30 | 'GET /storage/vol0/file.txt',
31 | 'GET /status/control?cmd=status&group=*',
32 | ]
33 | --- response_body_like eval
34 | [
35 | 'OK',
36 | 'nginxVersion'
37 | ]
38 |
39 |
--------------------------------------------------------------------------------
/t/007.control_status_group.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=status&group=server&zone=::main
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | 'GET /status/control?cmd=status&group=server&zone=::main',
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | 'hostName'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=status&group=server&zone=*
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | --- user_files eval
47 | [
48 | ['storage/control/file.txt' => 'server:OK']
49 | ]
50 | --- request eval
51 | [
52 | 'GET /storage/control/file.txt',
53 | 'GET /status/control?cmd=status&group=server&zone=*',
54 | ]
55 | --- response_body_like eval
56 | [
57 | 'OK',
58 | '{"serverZones.*localhost'
59 | ]
60 |
61 |
62 |
63 | === TEST 3: /status/control?cmd=status&group=filter&zone=*
64 | --- http_config
65 | vhost_traffic_status_zone;
66 | --- config
67 | location /status {
68 | vhost_traffic_status_display;
69 | vhost_traffic_status_display_format json;
70 | access_log off;
71 | }
72 | location ~ ^/storage/(.+)/.*$ {
73 | set $volume $1;
74 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
75 | }
76 | --- user_files eval
77 | [
78 | ['storage/vol0/file.txt' => 'filter:OK']
79 | ]
80 | --- request eval
81 | [
82 | 'GET /storage/vol0/file.txt',
83 | 'GET /status/control?cmd=status&group=filter&zone=*',
84 | ]
85 | --- response_body_like eval
86 | [
87 | 'OK',
88 | '{"filterZones.*storage::'
89 | ]
90 |
91 |
92 |
93 | === TEST 4: /status/control?cmd=status&group=upstream@group&zone=*
94 | --- http_config
95 | vhost_traffic_status_zone;
96 | upstream backend {
97 | server localhost;
98 | }
99 | server {
100 | server_name backend;
101 | }
102 | --- config
103 | location /status {
104 | vhost_traffic_status_display;
105 | vhost_traffic_status_display_format json;
106 | access_log off;
107 | }
108 | location /backend {
109 | proxy_set_header Host backend;
110 | proxy_pass http://backend;
111 | }
112 | --- user_files eval
113 | [
114 | ['backend/file.txt' => 'upstream@group:OK']
115 | ]
116 | --- request eval
117 | [
118 | 'GET /backend/file.txt',
119 | 'GET /status/control?cmd=status&group=upstream@group&zone=*',
120 | ]
121 | --- response_body_like eval
122 | [
123 | 'OK',
124 | '{"upstreamZones.*backend'
125 | ]
126 |
127 |
128 |
129 | === TEST 5: /status/control?cmd=status&group=upstream@alone&zone=*
130 | --- http_config
131 | vhost_traffic_status_zone;
132 | --- config
133 | location /status {
134 | vhost_traffic_status_display;
135 | vhost_traffic_status_display_format json;
136 | access_log off;
137 | }
138 | location /backend {
139 | proxy_set_header Host backend;
140 | proxy_pass http://localhost:1981;
141 | }
142 | --- tcp_listen: 1981
143 | --- tcp_reply eval
144 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
145 | --- request eval
146 | [
147 | 'GET /backend/file.txt',
148 | 'GET /status/control?cmd=status&group=upstream@alone&zone=*',
149 | ]
150 | --- response_body_like eval
151 | [
152 | 'OK',
153 | '{"::nogroups"'
154 | ]
155 |
156 |
157 |
158 | === TEST 6: /status/control?cmd=status&group=cache&zone=*
159 | --- http_config
160 | vhost_traffic_status_zone;
161 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
162 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
163 | upstream backend {
164 | server localhost;
165 | }
166 | server {
167 | server_name backend;
168 | }
169 | --- config
170 | location /status {
171 | vhost_traffic_status_display;
172 | vhost_traffic_status_display_format json;
173 | access_log off;
174 | }
175 | location /one {
176 | proxy_cache cache_one;
177 | proxy_cache_valid 200 10s;
178 | proxy_set_header Host backend;
179 | proxy_pass http://backend;
180 | }
181 | location /two {
182 | proxy_cache cache_two;
183 | proxy_cache_valid 200 10s;
184 | proxy_set_header Host backend;
185 | proxy_pass http://backend;
186 | }
187 | --- user_files eval
188 | [
189 | ['one/file.txt' => 'cache_one:OK'],
190 | ['two/file.txt' => 'cache_two:OK']
191 | ]
192 | --- request eval
193 | [
194 | 'GET /one/file.txt',
195 | 'GET /two/file.txt',
196 | 'GET /status/control?cmd=status&group=cache&zone=*'
197 | ]
198 | --- response_body_like eval
199 | [
200 | 'OK',
201 | 'OK',
202 | '{"cacheZones.*cache_(one|two)'
203 | ]
204 |
205 | === TEST 7: /status/control?cmd=status&group=upstream%40group&zone=%2A
206 | --- http_config
207 | vhost_traffic_status_zone;
208 | upstream backend {
209 | server localhost;
210 | }
211 | server {
212 | server_name backend;
213 | }
214 | --- config
215 | location /status {
216 | vhost_traffic_status_display;
217 | vhost_traffic_status_display_format json;
218 | access_log off;
219 | }
220 | location /backend {
221 | proxy_set_header Host backend;
222 | proxy_pass http://backend;
223 | }
224 | --- user_files eval
225 | [
226 | ['backend/file.txt' => 'upstream@group:OK']
227 | ]
228 | --- request eval
229 | [
230 | 'GET /backend/file.txt',
231 | 'GET /status/control?cmd=status&group=upstream%40group&zone=%2A',
232 | ]
233 | --- response_body_like eval
234 | [
235 | 'OK',
236 | '{"upstreamZones.*backend'
237 | ]
238 |
239 | === TEST 8: /status/control?cmd=status&group=upstream%40group&zone=%2a
240 | --- http_config
241 | vhost_traffic_status_zone;
242 | upstream backend {
243 | server localhost;
244 | }
245 | server {
246 | server_name backend;
247 | }
248 | --- config
249 | location /status {
250 | vhost_traffic_status_display;
251 | vhost_traffic_status_display_format json;
252 | access_log off;
253 | }
254 | location /backend {
255 | proxy_set_header Host backend;
256 | proxy_pass http://backend;
257 | }
258 | --- user_files eval
259 | [
260 | ['backend/file.txt' => 'upstream@group:OK']
261 | ]
262 | --- request eval
263 | [
264 | 'GET /backend/file.txt',
265 | 'GET /status/control?cmd=status&group=upstream%40group&zone=%2a',
266 | ]
267 | --- response_body_like eval
268 | [
269 | 'OK',
270 | '{"upstreamZones.*backend'
271 | ]
272 |
273 | === TEST 9: /status/control?cmd=status&group=server&zone=%3A%3Amain
274 | --- http_config
275 | vhost_traffic_status_zone;
276 | --- config
277 | location /status {
278 | vhost_traffic_status_display;
279 | vhost_traffic_status_display_format json;
280 | access_log off;
281 | }
282 | --- user_files eval
283 | [
284 | ['storage/control/file.txt' => 'server:OK']
285 | ]
286 | --- request eval
287 | [
288 | 'GET /storage/control/file.txt',
289 | 'GET /status/control?cmd=status&group=server&zone=%3A%3Amain',
290 | ]
291 | --- response_body_like eval
292 | [
293 | 'OK',
294 | 'hostName'
295 | ]
296 |
297 |
--------------------------------------------------------------------------------
/t/008.control_status_zone.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=status&group=server&zone=localhost
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | 'GET /status/control?cmd=status&group=server&zone=localhost',
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | '{"localhost"'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=status&group=filter&zone=storage::localhost@vol0
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | location ~ ^/storage/(.+)/.*$ {
47 | set $volume $1;
48 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
49 | }
50 | --- user_files eval
51 | [
52 | ['storage/vol0/file.txt' => 'filter:OK']
53 | ]
54 | --- request eval
55 | [
56 | 'GET /storage/vol0/file.txt',
57 | 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0',
58 | ]
59 | --- response_body_like eval
60 | [
61 | 'OK',
62 | '{"vol0"'
63 | ]
64 |
65 |
66 |
67 | === TEST 3: /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:80
68 | --- http_config
69 | vhost_traffic_status_zone;
70 | upstream backend {
71 | server 127.0.0.1;
72 | }
73 | server {
74 | server_name backend;
75 | }
76 | --- config
77 | location /status {
78 | vhost_traffic_status_display;
79 | vhost_traffic_status_display_format json;
80 | access_log off;
81 | }
82 | location /backend {
83 | proxy_set_header Host backend;
84 | proxy_pass http://backend;
85 | }
86 | --- user_files eval
87 | [
88 | ['backend/file.txt' => 'upstream@group:OK']
89 | ]
90 | --- request eval
91 | [
92 | 'GET /backend/file.txt',
93 | 'GET /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:80',
94 | ]
95 | --- response_body_like eval
96 | [
97 | 'OK',
98 | '{"server":"127.0.0.1:80"'
99 | ]
100 |
101 |
102 |
103 | === TEST 4: /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1981
104 | --- http_config
105 | vhost_traffic_status_zone;
106 | --- config
107 | location /status {
108 | vhost_traffic_status_display;
109 | vhost_traffic_status_display_format json;
110 | access_log off;
111 | }
112 | location /backend {
113 | proxy_set_header Host backend;
114 | proxy_pass http://127.0.0.1:1981;
115 | }
116 | --- tcp_listen: 1981
117 | --- tcp_reply eval
118 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
119 | --- request eval
120 | [
121 | 'GET /backend/file.txt',
122 | 'GET /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1981',
123 | ]
124 | --- response_body_like eval
125 | [
126 | 'OK',
127 | '{"server":"127.0.0.1:1981"'
128 | ]
129 |
130 |
131 |
132 | === TEST 5: /status/control?cmd=status&group=cache&zone=cache_one
133 | --- http_config
134 | vhost_traffic_status_zone;
135 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
136 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
137 | upstream backend {
138 | server 127.0.0.1;
139 | }
140 | server {
141 | server_name backend;
142 | }
143 | --- config
144 | location /status {
145 | vhost_traffic_status_display;
146 | vhost_traffic_status_display_format json;
147 | access_log off;
148 | }
149 | location /one {
150 | proxy_cache cache_one;
151 | proxy_cache_valid 200 10s;
152 | proxy_set_header Host backend;
153 | proxy_pass http://backend;
154 | }
155 | location /two {
156 | proxy_cache cache_two;
157 | proxy_cache_valid 200 10s;
158 | proxy_set_header Host backend;
159 | proxy_pass http://backend;
160 | }
161 | --- user_files eval
162 | [
163 | ['one/file.txt' => 'cache_one:OK'],
164 | ['two/file.txt' => 'cache_two:OK']
165 | ]
166 | --- request eval
167 | [
168 | 'GET /one/file.txt',
169 | 'GET /two/file.txt',
170 | 'GET /status/control?cmd=status&group=cache&zone=cache_one'
171 | ]
172 | --- response_body_like eval
173 | [
174 | 'OK',
175 | 'OK',
176 | '{"cache_one"'
177 | ]
178 |
179 | === TEST 6: /status/control?cmd=status&group=filter&zone=storage%3A%3Alocalhost%40vol0
180 | --- http_config
181 | vhost_traffic_status_zone;
182 | --- config
183 | location /status {
184 | vhost_traffic_status_display;
185 | vhost_traffic_status_display_format json;
186 | access_log off;
187 | }
188 | location ~ ^/storage/(.+)/.*$ {
189 | set $volume $1;
190 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
191 | }
192 | --- user_files eval
193 | [
194 | ['storage/vol0/file.txt' => 'filter:OK']
195 | ]
196 | --- request eval
197 | [
198 | 'GET /storage/vol0/file.txt',
199 | 'GET /status/control?cmd=status&group=filter&zone=storage%3A%3Alocalhost%40vol0',
200 | ]
201 | --- response_body_like eval
202 | [
203 | 'OK',
204 | '{"vol0"'
205 | ]
206 |
207 | === TEST 7: /status/control?cmd=status&group=upstream%40alone&zone=127.0.0.1%3A1981
208 | --- http_config
209 | vhost_traffic_status_zone;
210 | --- config
211 | location /status {
212 | vhost_traffic_status_display;
213 | vhost_traffic_status_display_format json;
214 | access_log off;
215 | }
216 | location /backend {
217 | proxy_set_header Host backend;
218 | proxy_pass http://127.0.0.1:1981;
219 | }
220 | --- tcp_listen: 1981
221 | --- tcp_reply eval
222 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
223 | --- request eval
224 | [
225 | 'GET /backend/file.txt',
226 | 'GET /status/control?cmd=status&group=upstream%40alone&zone=127.0.0.1%3A1981',
227 | ]
228 | --- response_body_like eval
229 | [
230 | 'OK',
231 | '{"server":"127.0.0.1:1981"'
232 | ]
233 |
234 | === TEST 8: /status/control?cmd=status&group=filter&zone=storage%3a%3alocalhost%40vol0
235 | --- http_config
236 | vhost_traffic_status_zone;
237 | --- config
238 | location /status {
239 | vhost_traffic_status_display;
240 | vhost_traffic_status_display_format json;
241 | access_log off;
242 | }
243 | location ~ ^/storage/(.+)/.*$ {
244 | set $volume $1;
245 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
246 | }
247 | --- user_files eval
248 | [
249 | ['storage/vol0/file.txt' => 'filter:OK']
250 | ]
251 | --- request eval
252 | [
253 | 'GET /storage/vol0/file.txt',
254 | 'GET /status/control?cmd=status&group=filter&zone=storage%3A%3Alocalhost%40vol0',
255 | ]
256 | --- response_body_like eval
257 | [
258 | 'OK',
259 | '{"vol0"'
260 | ]
261 |
262 |
--------------------------------------------------------------------------------
/t/009.control_reset_fully.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=reset&group=*
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | location ~ ^/storage/(.+)/.*$ {
21 | set $volume $1;
22 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
23 | }
24 | --- user_files eval
25 | [
26 | ['storage/vol0/file.txt' => 'vol0:OK']
27 | ]
28 | --- request eval
29 | [
30 | 'GET /storage/vol0/file.txt',
31 | 'GET /status/control?cmd=reset&group=*',
32 | ]
33 | --- response_body_like eval
34 | [
35 | 'OK',
36 | '"processingCounts":[1-9]'
37 | ]
38 |
39 |
--------------------------------------------------------------------------------
/t/010.control_reset_group.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=reset&group=server&zone=*
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | "GET /status/control?cmd=reset&group=server&zone=*",
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | '"processingCounts":[1-9]'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=reset&group=filter&zone=*
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | location ~ ^/storage/(.+)/.*$ {
47 | set $volume $1;
48 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
49 | }
50 | --- user_files eval
51 | [
52 | ['storage/vol0/file.txt' => 'filter:OK']
53 | ]
54 | --- request eval
55 | [
56 | 'GET /storage/vol0/file.txt',
57 | 'GET /status/control?cmd=reset&group=filter&zone=*',
58 | ]
59 | --- response_body_like eval
60 | [
61 | 'OK',
62 | '"processingCounts":[1-9]'
63 | ]
64 |
65 |
66 |
67 | === TEST 3: /status/control?cmd=reset&group=upstream@group&zone=*
68 | --- http_config
69 | vhost_traffic_status_zone;
70 | upstream backend {
71 | server 127.0.0.1;
72 | }
73 | server {
74 | server_name backend;
75 | }
76 | --- config
77 | location /status {
78 | vhost_traffic_status_display;
79 | vhost_traffic_status_display_format json;
80 | access_log off;
81 | }
82 | location /backend {
83 | proxy_set_header Host backend;
84 | proxy_pass http://backend;
85 | }
86 | --- user_files eval
87 | [
88 | ['backend/file.txt' => 'upstream@group:OK']
89 | ]
90 | --- request eval
91 | [
92 | 'GET /backend/file.txt',
93 | 'GET /status/control?cmd=reset&group=upstream@group&zone=*',
94 | ]
95 | --- response_body_like eval
96 | [
97 | 'OK',
98 | '"processingCounts":[1-9]'
99 | ]
100 |
101 |
102 |
103 | === TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=*
104 | --- http_config
105 | vhost_traffic_status_zone;
106 | --- config
107 | location /status {
108 | vhost_traffic_status_display;
109 | vhost_traffic_status_display_format json;
110 | access_log off;
111 | }
112 | location /backend {
113 | proxy_set_header Host backend;
114 | proxy_pass http://localhost:1981;
115 | }
116 | --- tcp_listen: 1981
117 | --- tcp_reply eval
118 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
119 | --- request eval
120 | [
121 | 'GET /backend/file.txt',
122 | 'GET /status/control?cmd=reset&group=upstream@alone&zone=*',
123 | ]
124 | --- response_body_like eval
125 | [
126 | 'OK',
127 | '"processingCounts":[1-9]'
128 | ]
129 |
130 |
131 |
132 | === TEST 5: /status/control?cmd=reset&group=cache&zone=*
133 | --- http_config
134 | vhost_traffic_status_zone;
135 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
136 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
137 | upstream backend {
138 | server 127.0.0.1;
139 | }
140 | server {
141 | server_name backend;
142 | }
143 | --- config
144 | location /status {
145 | vhost_traffic_status_display;
146 | vhost_traffic_status_display_format json;
147 | access_log off;
148 | }
149 | location /one {
150 | proxy_cache cache_one;
151 | proxy_cache_valid 200 10s;
152 | proxy_set_header Host backend;
153 | proxy_pass http://backend;
154 | }
155 | location /two {
156 | proxy_cache cache_two;
157 | proxy_cache_valid 200 10s;
158 | proxy_set_header Host backend;
159 | proxy_pass http://backend;
160 | }
161 | --- user_files eval
162 | [
163 | ['one/file.txt' => 'cache_one:OK'],
164 | ['two/file.txt' => 'cache_two:OK']
165 | ]
166 | --- request eval
167 | [
168 | 'GET /one/file.txt',
169 | 'GET /two/file.txt',
170 | 'GET /status/control?cmd=reset&group=cache&zone=*'
171 | ]
172 | --- response_body_like eval
173 | [
174 | 'OK',
175 | 'OK',
176 | '"processingCounts":[1-9]'
177 | ]
178 |
--------------------------------------------------------------------------------
/t/011.control_reset_zone.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=reset&group=server&zone=localhost
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | 'GET /status/control?cmd=reset&group=server&zone=localhost',
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | '"processingCounts":[1-9]'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=reset&group=filter&zone=storage::localhost@vol0
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | location ~ ^/storage/(.+)/.*$ {
47 | set $volume $1;
48 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
49 | }
50 | --- user_files eval
51 | [
52 | ['storage/vol0/file.txt' => 'filter:OK']
53 | ]
54 | --- request eval
55 | [
56 | 'GET /storage/vol0/file.txt',
57 | 'GET /status/control?cmd=reset&group=filter&zone=storage::localhost@vol0',
58 | ]
59 | --- response_body_like eval
60 | [
61 | 'OK',
62 | '"processingCounts":[1-9]'
63 | ]
64 |
65 |
66 |
67 | === TEST 3: /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:80
68 | --- http_config
69 | vhost_traffic_status_zone;
70 | upstream backend {
71 | server 127.0.0.1;
72 | }
73 | server {
74 | server_name backend;
75 | }
76 | --- config
77 | location /status {
78 | vhost_traffic_status_display;
79 | vhost_traffic_status_display_format json;
80 | access_log off;
81 | }
82 | location /backend {
83 | proxy_set_header Host backend;
84 | proxy_pass http://backend;
85 | }
86 | --- user_files eval
87 | [
88 | ['backend/file.txt' => 'upstream@group:OK']
89 | ]
90 | --- request eval
91 | [
92 | 'GET /backend/file.txt',
93 | 'GET /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:80',
94 | ]
95 | --- response_body_like eval
96 | [
97 | 'OK',
98 | '"processingCounts":[1-9]'
99 | ]
100 |
101 |
102 |
103 | === TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1981
104 | --- http_config
105 | vhost_traffic_status_zone;
106 | --- config
107 | location /status {
108 | vhost_traffic_status_display;
109 | vhost_traffic_status_display_format json;
110 | access_log off;
111 | }
112 | location /backend {
113 | proxy_set_header Host backend;
114 | proxy_pass http://127.0.0.1:1981;
115 | }
116 | --- tcp_listen: 1981
117 | --- tcp_reply eval
118 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
119 | --- request eval
120 | [
121 | 'GET /backend/file.txt',
122 | 'GET /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1981',
123 | ]
124 | --- response_body_like eval
125 | [
126 | 'OK',
127 | '"processingCounts":[1-9]'
128 | ]
129 |
130 |
131 |
132 | === TEST 5: /status/control?cmd=reset&group=cache&zone=cache_one
133 | --- http_config
134 | vhost_traffic_status_zone;
135 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
136 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
137 | upstream backend {
138 | server 127.0.0.1;
139 | }
140 | server {
141 | server_name backend;
142 | }
143 | --- config
144 | location /status {
145 | vhost_traffic_status_display;
146 | vhost_traffic_status_display_format json;
147 | access_log off;
148 | }
149 | location /one {
150 | proxy_cache cache_one;
151 | proxy_cache_valid 200 10s;
152 | proxy_set_header Host backend;
153 | proxy_pass http://backend;
154 | }
155 | location /two {
156 | proxy_cache cache_two;
157 | proxy_cache_valid 200 10s;
158 | proxy_set_header Host backend;
159 | proxy_pass http://backend;
160 | }
161 | --- user_files eval
162 | [
163 | ['one/file.txt' => 'cache_one:OK'],
164 | ['two/file.txt' => 'cache_two:OK']
165 | ]
166 | --- request eval
167 | [
168 | 'GET /one/file.txt',
169 | 'GET /two/file.txt',
170 | 'GET /status/control?cmd=reset&group=cache&zone=cache_one'
171 | ]
172 | --- response_body_like eval
173 | [
174 | 'OK',
175 | 'OK',
176 | '"processingCounts":[1-9]'
177 | ]
178 |
--------------------------------------------------------------------------------
/t/012.control_delete_fully.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=delete&group=*
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | location ~ ^/storage/(.+)/.*$ {
21 | set $volume $1;
22 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
23 | }
24 | --- user_files eval
25 | [
26 | ['storage/vol0/file.txt' => 'vol0:OK']
27 | ]
28 | --- request eval
29 | [
30 | 'GET /storage/vol0/file.txt',
31 | 'GET /status/control?cmd=delete&group=*',
32 | ]
33 | --- response_body_like eval
34 | [
35 | 'OK',
36 | '"processingCounts":[1-9]'
37 | ]
38 |
39 |
--------------------------------------------------------------------------------
/t/013.control_delete_group.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=delete&group=server&zone=*
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | "GET /status/control?cmd=delete&group=server&zone=*",
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | '"processingCounts":[1-9]'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=delete&group=filter&zone=*
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | location ~ ^/storage/(.+)/.*$ {
47 | set $volume $1;
48 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
49 | }
50 | --- user_files eval
51 | [
52 | ['storage/vol0/file.txt' => 'filter:OK']
53 | ]
54 | --- request eval
55 | [
56 | 'GET /storage/vol0/file.txt',
57 | 'GET /status/control?cmd=delete&group=filter&zone=*',
58 | ]
59 | --- response_body_like eval
60 | [
61 | 'OK',
62 | '"processingCounts":[1-9]'
63 | ]
64 |
65 |
66 |
67 | === TEST 3: /status/control?cmd=delete&group=upstream@group&zone=*
68 | --- http_config
69 | vhost_traffic_status_zone;
70 | upstream backend {
71 | server 127.0.0.1;
72 | }
73 | server {
74 | server_name backend;
75 | }
76 | --- config
77 | location /status {
78 | vhost_traffic_status_display;
79 | vhost_traffic_status_display_format json;
80 | access_log off;
81 | }
82 | location /backend {
83 | proxy_set_header Host backend;
84 | proxy_pass http://backend;
85 | }
86 | --- user_files eval
87 | [
88 | ['backend/file.txt' => 'upstream@group:OK']
89 | ]
90 | --- request eval
91 | [
92 | 'GET /backend/file.txt',
93 | 'GET /status/control?cmd=delete&group=upstream@group&zone=*',
94 | ]
95 | --- response_body_like eval
96 | [
97 | 'OK',
98 | '"processingCounts":[1-9]'
99 | ]
100 |
101 |
102 |
103 | === TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=*
104 | --- http_config
105 | vhost_traffic_status_zone;
106 | --- config
107 | location /status {
108 | vhost_traffic_status_display;
109 | vhost_traffic_status_display_format json;
110 | access_log off;
111 | }
112 | location /backend {
113 | proxy_set_header Host backend;
114 | proxy_pass http://localhost:1981;
115 | }
116 | --- tcp_listen: 1981
117 | --- tcp_reply eval
118 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
119 | --- request eval
120 | [
121 | 'GET /backend/file.txt',
122 | 'GET /status/control?cmd=delete&group=upstream@alone&zone=*',
123 | ]
124 | --- response_body_like eval
125 | [
126 | 'OK',
127 | '"processingCounts":[1-9]'
128 | ]
129 |
130 |
131 |
132 | === TEST 5: /status/control?cmd=delete&group=cache&zone=*
133 | --- http_config
134 | vhost_traffic_status_zone;
135 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
136 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
137 | upstream backend {
138 | server 127.0.0.1;
139 | }
140 | server {
141 | server_name backend;
142 | }
143 | --- config
144 | location /status {
145 | vhost_traffic_status_display;
146 | vhost_traffic_status_display_format json;
147 | access_log off;
148 | }
149 | location /one {
150 | proxy_cache cache_one;
151 | proxy_cache_valid 200 10s;
152 | proxy_set_header Host backend;
153 | proxy_pass http://backend;
154 | }
155 | location /two {
156 | proxy_cache cache_two;
157 | proxy_cache_valid 200 10s;
158 | proxy_set_header Host backend;
159 | proxy_pass http://backend;
160 | }
161 | --- user_files eval
162 | [
163 | ['one/file.txt' => 'cache_one:OK'],
164 | ['two/file.txt' => 'cache_two:OK']
165 | ]
166 | --- request eval
167 | [
168 | 'GET /one/file.txt',
169 | 'GET /two/file.txt',
170 | 'GET /status/control?cmd=delete&group=cache&zone=*'
171 | ]
172 | --- response_body_like eval
173 | [
174 | 'OK',
175 | 'OK',
176 | '"processingCounts":[1-9]'
177 | ]
178 |
--------------------------------------------------------------------------------
/t/014.control_delete_zone.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 4 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: /status/control?cmd=delete&group=server&zone=localhost
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_format json;
18 | access_log off;
19 | }
20 | --- user_files eval
21 | [
22 | ['storage/control/file.txt' => 'server:OK']
23 | ]
24 | --- request eval
25 | [
26 | 'GET /storage/control/file.txt',
27 | 'GET /status/control?cmd=delete&group=server&zone=localhost',
28 | ]
29 | --- response_body_like eval
30 | [
31 | 'OK',
32 | '"processingCounts":[1-9]'
33 | ]
34 |
35 |
36 |
37 | === TEST 2: /status/control?cmd=delete&group=filter&zone=storage::localhost@vol0
38 | --- http_config
39 | vhost_traffic_status_zone;
40 | --- config
41 | location /status {
42 | vhost_traffic_status_display;
43 | vhost_traffic_status_display_format json;
44 | access_log off;
45 | }
46 | location ~ ^/storage/(.+)/.*$ {
47 | set $volume $1;
48 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
49 | }
50 | --- user_files eval
51 | [
52 | ['storage/vol0/file.txt' => 'filter:OK']
53 | ]
54 | --- request eval
55 | [
56 | 'GET /storage/vol0/file.txt',
57 | 'GET /status/control?cmd=delete&group=filter&zone=storage::localhost@vol0',
58 | ]
59 | --- response_body_like eval
60 | [
61 | 'OK',
62 | '"processingCounts":[1-9]'
63 | ]
64 |
65 |
66 |
67 | === TEST 3: /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:80
68 | --- http_config
69 | vhost_traffic_status_zone;
70 | upstream backend {
71 | server 127.0.0.1;
72 | }
73 | server {
74 | server_name backend;
75 | }
76 | --- config
77 | location /status {
78 | vhost_traffic_status_display;
79 | vhost_traffic_status_display_format json;
80 | access_log off;
81 | }
82 | location /backend {
83 | proxy_set_header Host backend;
84 | proxy_pass http://backend;
85 | }
86 | --- user_files eval
87 | [
88 | ['backend/file.txt' => 'upstream@group:OK']
89 | ]
90 | --- request eval
91 | [
92 | 'GET /backend/file.txt',
93 | 'GET /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:80',
94 | ]
95 | --- response_body_like eval
96 | [
97 | 'OK',
98 | '"processingCounts":[1-9]'
99 | ]
100 |
101 |
102 |
103 | === TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1981
104 | --- http_config
105 | vhost_traffic_status_zone;
106 | --- config
107 | location /status {
108 | vhost_traffic_status_display;
109 | vhost_traffic_status_display_format json;
110 | access_log off;
111 | }
112 | location /backend {
113 | proxy_set_header Host backend;
114 | proxy_pass http://127.0.0.1:1981;
115 | }
116 | --- tcp_listen: 1981
117 | --- tcp_reply eval
118 | "HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK"
119 | --- request eval
120 | [
121 | 'GET /backend/file.txt',
122 | 'GET /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1981',
123 | ]
124 | --- response_body_like eval
125 | [
126 | 'OK',
127 | '"processingCounts":[1-9]'
128 | ]
129 |
130 |
131 |
132 | === TEST 5: /status/control?cmd=delete&group=cache&zone=cache_one
133 | --- http_config
134 | vhost_traffic_status_zone;
135 | proxy_cache_path /tmp/cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
136 | proxy_cache_path /tmp/cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m;
137 | upstream backend {
138 | server 127.0.0.1;
139 | }
140 | server {
141 | server_name backend;
142 | }
143 | --- config
144 | location /status {
145 | vhost_traffic_status_display;
146 | vhost_traffic_status_display_format json;
147 | access_log off;
148 | }
149 | location /one {
150 | proxy_cache cache_one;
151 | proxy_cache_valid 200 10s;
152 | proxy_set_header Host backend;
153 | proxy_pass http://backend;
154 | }
155 | location /two {
156 | proxy_cache cache_two;
157 | proxy_cache_valid 200 10s;
158 | proxy_set_header Host backend;
159 | proxy_pass http://backend;
160 | }
161 | --- user_files eval
162 | [
163 | ['one/file.txt' => 'cache_one:OK'],
164 | ['two/file.txt' => 'cache_two:OK']
165 | ]
166 | --- request eval
167 | [
168 | 'GET /one/file.txt',
169 | 'GET /two/file.txt',
170 | 'GET /status/control?cmd=delete&group=cache&zone=cache_one'
171 | ]
172 | --- response_body_like eval
173 | [
174 | 'OK',
175 | 'OK',
176 | '"processingCounts":[1-9]'
177 | ]
178 |
--------------------------------------------------------------------------------
/t/015.vts_variables_by_lua.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 6;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST1: access embeded variables starting with a $vts_* by lua
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /variables {
16 | access_by_lua_block {
17 | local i
18 | local variables = {
19 | ngx.var.vts_request_counter,
20 | ngx.var.vts_in_bytes,
21 | ngx.var.vts_out_bytes,
22 | ngx.var.vts_1xx_counter,
23 | ngx.var.vts_2xx_counter,
24 | ngx.var.vts_3xx_counter,
25 | ngx.var.vts_4xx_counter,
26 | ngx.var.vts_5xx_counter,
27 | ngx.var.vts_request_time_counter,
28 | ngx.var.vts_request_time,
29 | ngx.var.vts_cache_miss_counter,
30 | ngx.var.vts_cache_bypass_counter,
31 | ngx.var.vts_cache_expired_counter,
32 | ngx.var.vts_cache_stale_counter,
33 | ngx.var.vts_cache_updating_counter,
34 | ngx.var.vts_cache_revalidated_counter,
35 | ngx.var.vts_cache_hit_counter,
36 | ngx.var.vts_cache_scarce_counter
37 | }
38 | ngx.print("embeded_variables: 18, find_variables: ", table.getn(variables), ", variables: ");
39 | for i=1, table.getn(variables) do
40 | if variables[i] then
41 | ngx.print(i, ":[", variables[i], "] ")
42 | else
43 | ngx.print(i, ":[nil] ")
44 | end
45 | end
46 | }
47 | }
48 | location ~ ^/storage/(.+)/.*$ {
49 | set $volume $1;
50 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
51 | }
52 | --- user_files eval
53 | [
54 | ['storage/access/file.txt' => 'access:OK']
55 | ]
56 | --- request eval
57 | [
58 | 'GET /storage/access/file.txt',
59 | 'GET /variables',
60 | 'GET /variables'
61 | ]
62 | --- response_body_like eval
63 | [
64 | 'OK',
65 | 'find_variables: 18',
66 | 'find_variables: 18'
67 | ]
68 |
--------------------------------------------------------------------------------
/t/016.limit_traffic_by_lua.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 8;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST1: limit traffic using $vts_* by lua
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | set $limit_in 200;
16 | set $limit_out 256;
17 | access_by_lua_block {
18 | local limits = {
19 | ["request"] = tonumber(ngx.var.limit_request),
20 | ["in"] = tonumber(ngx.var.limit_in),
21 | ["out"] = tonumber(ngx.var.limit_out),
22 | ["1xx"] = tonumber(ngx.var.limit_1xx),
23 | ["2xx"] = tonumber(ngx.var.limit_2xx),
24 | ["3xx"] = tonumber(ngx.var.limit_3xx),
25 | ["4xx"] = tonumber(ngx.var.limit_4xx),
26 | ["5xx"] = tonumber(ngx.var.limit_5xx),
27 | ["miss"] = tonumber(ngx.var.limit_miss),
28 | ["bypass"] = tonumber(ngx.var.limit_bypass),
29 | ["expired"] = tonumber(ngx.var.limit_expired),
30 | ["stale"] = tonumber(ngx.var.limit_stale),
31 | ["updating"] = tonumber(ngx.var.limit_updating),
32 | ["revalidated"] = tonumber(ngx.var.limit_revalidated),
33 | ["hit"] = tonumber(ngx.var.limit_hit),
34 | ["scarce"] = tonumber(ngx.var.limit_scarce)
35 | }
36 |
37 | local stats = {
38 | ["request"] = limits["request"] and tonumber(ngx.var.vts_request_counter),
39 | ["in"] = limits["in"] and tonumber(ngx.var.vts_in_bytes),
40 | ["out"] = limits["out"] and tonumber(ngx.var.vts_out_bytes),
41 | ["1xx"] = limits["1xx"] and tonumber(ngx.var.vts_1xx_counter),
42 | ["2xx"] = limits["2xx"] and tonumber(ngx.var.vts_2xx_counter),
43 | ["3xx"] = limits["3xx"] and tonumber(ngx.var.vts_3xx_counter),
44 | ["4xx"] = limits["4xx"] and tonumber(ngx.var.vts_4xx_counter),
45 | ["5xx"] = limits["5xx"] and tonumber(ngx.var.vts_5xx_counter),
46 | ["miss"] = limits["miss"] and tonumber(ngx.var.vts_cache_miss_counter),
47 | ["bypass"] = limits["bypass"] and tonumber(ngx.var.vts_cache_bypass_counter),
48 | ["expired"] = limits["expired"] and tonumber(ngx.var.vts_cache_expired_counter),
49 | ["stale"] = limits["stale"] and tonumber(ngx.var.vts_cache_stale_counter),
50 | ["updating"] = limits["updating"] and tonumber(ngx.var.vts_cache_updating_counter),
51 | ["revalidated"] = limits["revalidated"] and tonumber(ngx.var.vts_cache_revalidated_counter),
52 | ["hit"] = limits["hit"] and tonumber(ngx.var.vts_cache_hit_counter),
53 | ["scarce"] = limits["scarce"] and tonumber(ngx.var.vts_cache_scarce_counter)
54 | }
55 |
56 | for k,v in pairs(limits) do
57 | if stats[k] and stats[k] > v then
58 | ngx.say("exceeded ", k, " traffic limit[", v, "] < current[", stats[k], "]");
59 | end
60 | end
61 | }
62 | location ~ ^/storage/(.+)/.*$ {
63 | set $volume $1;
64 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
65 | }
66 | --- user_files eval
67 | [
68 | ['storage/limit/file.txt' => 'limit:OK']
69 | ]
70 | --- request eval
71 | [
72 | 'GET /storage/limit/file.txt',
73 | 'GET /storage/limit/file.txt',
74 | 'GET /storage/limit/file.txt',
75 | 'GET /storage/limit/file.txt'
76 | ]
77 | --- response_body_like eval
78 | [
79 | 'OK',
80 | 'OK',
81 | 'exceeded',
82 | 'exceeded'
83 | ]
84 |
--------------------------------------------------------------------------------
/t/017.limit_traffic.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 12;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: vhost_traffic_status_limit_traffic request:n 402
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location ~ / {
16 | set $member request;
17 | vhost_traffic_status_limit_traffic $member:4 402;
18 | }
19 | error_page 402 /storage/limit/402.txt;
20 | location = /storage/limit/402.txt {
21 | internal;
22 | }
23 | --- user_files eval
24 | [
25 | ['storage/limit/file.txt' => 'server:OK'],
26 | ['storage/limit/402.txt' => 'limited:OK']
27 | ]
28 | --- request eval
29 | [
30 | 'GET /storage/limit/file.txt',
31 | 'GET /storage/limit/file.txt',
32 | 'GET /storage/limit/file.txt',
33 | 'GET /storage/limit/file.txt',
34 | 'GET /storage/limit/file.txt',
35 | 'GET /storage/limit/file.txt'
36 | ]
37 | --- error_code eval
38 | [
39 | 200,
40 | 200,
41 | 200,
42 | 200,
43 | 200,
44 | 402
45 | ]
46 | --- response_body_like eval
47 | [
48 | 'OK',
49 | 'OK',
50 | 'OK',
51 | 'OK',
52 | 'OK',
53 | 'OK'
54 | ]
55 |
56 |
57 |
58 | === TEST 2: vhost_traffic_status_limit_traffic in:n
59 | --- http_config
60 | vhost_traffic_status_zone;
61 | --- config
62 | location ~ / {
63 | vhost_traffic_status_limit_traffic in:320;
64 | }
65 | error_page 503 /storage/limit/503.txt;
66 | location = /storage/limit/503.txt {
67 | internal;
68 | }
69 | --- user_files eval
70 | [
71 | ['storage/limit/file.txt' => 'server:OK'],
72 | ['storage/limit/503.txt' => 'limited:OK']
73 | ]
74 | --- request eval
75 | [
76 | 'GET /storage/limit/file.txt',
77 | 'GET /storage/limit/file.txt',
78 | 'GET /storage/limit/file.txt',
79 | 'GET /storage/limit/file.txt',
80 | 'GET /storage/limit/file.txt',
81 | 'GET /storage/limit/file.txt'
82 | ]
83 | --- error_code eval
84 | [
85 | 200,
86 | 200,
87 | 200,
88 | 200,
89 | 200,
90 | 503
91 | ]
92 | --- response_body_like eval
93 | [
94 | 'OK',
95 | 'OK',
96 | 'OK',
97 | 'OK',
98 | 'OK',
99 | 'OK'
100 | ]
101 |
102 |
103 |
104 | === TEST 3: vhost_traffic_status_limit_traffic out:n
105 | --- http_config
106 | vhost_traffic_status_zone;
107 | --- config
108 | location ~ / {
109 | vhost_traffic_status_limit_traffic out:1024;
110 | }
111 | error_page 503 /storage/limit/503.txt;
112 | location = /storage/limit/503.txt {
113 | internal;
114 | }
115 | --- user_files eval
116 | [
117 | ['storage/limit/file.txt' => 'server:OK'],
118 | ['storage/limit/503.txt' => 'limited:OK']
119 | ]
120 | --- request eval
121 | [
122 | 'GET /storage/limit/file.txt',
123 | 'GET /storage/limit/file.txt',
124 | 'GET /storage/limit/file.txt',
125 | 'GET /storage/limit/file.txt',
126 | 'GET /storage/limit/file.txt',
127 | 'GET /storage/limit/file.txt'
128 | ]
129 | --- error_code eval
130 | [
131 | 200,
132 | 200,
133 | 200,
134 | 200,
135 | 200,
136 | 503
137 | ]
138 | --- response_body_like eval
139 | [
140 | 'OK',
141 | 'OK',
142 | 'OK',
143 | 'OK',
144 | 'OK',
145 | 'OK'
146 | ]
147 |
148 |
149 |
150 | === TEST 4: vhost_traffic_status_limit off
151 | --- http_config
152 | vhost_traffic_status_zone;
153 | vhost_traffic_status_limit off;
154 | --- config
155 | location ~ / {
156 | set $member request;
157 | vhost_traffic_status_limit_traffic $member:4;
158 | }
159 | error_page 503 /storage/limit/503.txt;
160 | location = /storage/limit/503.txt {
161 | internal;
162 | }
163 | --- user_files eval
164 | [
165 | ['storage/limit/file.txt' => 'server:OK'],
166 | ['storage/limit/503.txt' => 'limited:OK']
167 | ]
168 | --- request eval
169 | [
170 | 'GET /storage/limit/file.txt',
171 | 'GET /storage/limit/file.txt',
172 | 'GET /storage/limit/file.txt',
173 | 'GET /storage/limit/file.txt',
174 | 'GET /storage/limit/file.txt',
175 | 'GET /storage/limit/file.txt'
176 | ]
177 | --- error_code eval
178 | [
179 | 200,
180 | 200,
181 | 200,
182 | 200,
183 | 200,
184 | 200
185 | ]
186 | --- response_body_like eval
187 | [
188 | 'OK',
189 | 'OK',
190 | 'OK',
191 | 'OK',
192 | 'OK',
193 | 'OK'
194 | ]
195 |
--------------------------------------------------------------------------------
/t/018.limit_traffic_by_set_key.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 11 + 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: vhost_traffic_status_limit_traffic_by_set_key FG@group@name request:n 402
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location ~ ^/storage/(.+)/.*$ {
16 | set $volume $1;
17 | set $member request;
18 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
19 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume $member:4 402;
20 | }
21 | error_page 402 /storage/limit/402.txt;
22 | location = /storage/limit/402.txt {
23 | internal;
24 | }
25 | --- user_files eval
26 | [
27 | ['storage/vol0/file.txt' => 'vol0:OK'],
28 | ['storage/limit/402.txt' => 'limited:OK']
29 | ]
30 | --- request eval
31 | [
32 | 'GET /storage/vol0/file.txt',
33 | 'GET /storage/vol0/file.txt',
34 | 'GET /storage/vol0/file.txt',
35 | 'GET /storage/vol0/file.txt',
36 | 'GET /storage/vol0/file.txt',
37 | 'GET /storage/vol0/file.txt',
38 | ]
39 | --- error_code eval
40 | [
41 | 200,
42 | 200,
43 | 200,
44 | 200,
45 | 200,
46 | 402
47 | ]
48 | --- response_body_like eval
49 | [
50 | 'OK',
51 | 'OK',
52 | 'OK',
53 | 'OK',
54 | 'OK',
55 | 'OK'
56 | ]
57 |
58 |
59 |
60 | === TEST 2: vhost_traffic_status_limit_traffic_by_set_key FG@group@name in:n
61 | --- http_config
62 | vhost_traffic_status_zone;
63 | --- config
64 | location ~ ^/storage/(.+)/.*$ {
65 | set $volume $1;
66 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
67 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume in:300;
68 | }
69 | error_page 503 /storage/limit/503.txt;
70 | location = /storage/limit/503.txt {
71 | internal;
72 | }
73 | --- user_files eval
74 | [
75 | ['storage/vol0/file.txt' => 'vol0:OK'],
76 | ['storage/limit/503.txt' => 'limited:OK']
77 | ]
78 | --- request eval
79 | [
80 | 'GET /storage/vol0/file.txt',
81 | 'GET /storage/vol0/file.txt',
82 | 'GET /storage/vol0/file.txt',
83 | 'GET /storage/vol0/file.txt',
84 | 'GET /storage/vol0/file.txt',
85 | 'GET /storage/vol0/file.txt',
86 | ]
87 | --- error_code eval
88 | [
89 | 200,
90 | 200,
91 | 200,
92 | 200,
93 | 200,
94 | 503
95 | ]
96 | --- response_body_like eval
97 | [
98 | 'OK',
99 | 'OK',
100 | 'OK',
101 | 'OK',
102 | 'OK',
103 | 'OK'
104 | ]
105 |
106 |
107 |
108 | === TEST 3: vhost_traffic_status_limit_traffic_by_set_key FG@group@name out:n
109 | --- http_config
110 | vhost_traffic_status_zone;
111 | --- config
112 | location ~ ^/storage/(.+)/.*$ {
113 | set $volume $1;
114 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
115 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume out:1024;
116 | }
117 | error_page 503 /storage/limit/503.txt;
118 | location = /storage/limit/503.txt {
119 | internal;
120 | }
121 | --- user_files eval
122 | [
123 | ['storage/vol0/file.txt' => 'vol0:OK'],
124 | ['storage/limit/503.txt' => 'limited:OK']
125 | ]
126 | --- request eval
127 | [
128 | 'GET /storage/vol0/file.txt',
129 | 'GET /storage/vol0/file.txt',
130 | 'GET /storage/vol0/file.txt',
131 | 'GET /storage/vol0/file.txt',
132 | 'GET /storage/vol0/file.txt',
133 | 'GET /storage/vol0/file.txt',
134 | ]
135 | --- error_code eval
136 | [
137 | 200,
138 | 200,
139 | 200,
140 | 200,
141 | 200,
142 | 503
143 | ]
144 | --- response_body_like eval
145 | [
146 | 'OK',
147 | 'OK',
148 | 'OK',
149 | 'OK',
150 | 'OK',
151 | 'OK'
152 | ]
153 |
154 |
155 |
156 | === TEST 4: vhost_traffic_status_limit_traffic_by_set_key UG@group@name request:n
157 | --- http_config
158 | vhost_traffic_status_zone;
159 | upstream backend {
160 | server 127.0.0.1;
161 | }
162 | server {
163 | server_name backend;
164 | }
165 | --- config
166 | location /backend {
167 | vhost_traffic_status_limit_traffic_by_set_key UG@backend@127.0.0.1:80 request:3;
168 | proxy_set_header Host backend;
169 | proxy_pass http://backend;
170 | }
171 | error_page 503 /backend/limit/503.txt;
172 | location = /backend/limit/503.txt {
173 | internal;
174 | }
175 | --- user_files eval
176 | [
177 | ['backend/file.txt' => 'backend:OK'],
178 | ['backend/limit/503.txt' => 'limited:OK']
179 | ]
180 | --- request eval
181 | [
182 | 'GET /backend/file.txt',
183 | 'GET /backend/file.txt',
184 | 'GET /backend/file.txt',
185 | 'GET /backend/file.txt',
186 | 'GET /backend/file.txt',
187 | ]
188 | --- error_code eval
189 | [
190 | 200,
191 | 200,
192 | 200,
193 | 200,
194 | 503,
195 | ]
196 | --- response_body_like eval
197 | [
198 | 'OK',
199 | 'OK',
200 | 'OK',
201 | 'OK',
202 | 'OK',
203 | ]
204 |
--------------------------------------------------------------------------------
/t/019.limit_traffic_check_duplicate.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 12;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: limit_check_duplicate on
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | error_page 503 /storage/limit/503.txt;
16 | location = /storage/limit/503.txt {
17 | internal;
18 | }
19 | location ~ ^/storage/(.+)/.*$ {
20 | set $volume $1;
21 | vhost_traffic_status_limit_check_duplicate on;
22 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
23 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:8;
24 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:4;
25 | }
26 | --- user_files eval
27 | [
28 | ['storage/vol0/file.txt' => 'vol0:OK'],
29 | ['storage/limit/503.txt' => 'limited:OK']
30 | ]
31 | --- request eval
32 | [
33 | 'GET /storage/vol0/file.txt',
34 | 'GET /storage/vol0/file.txt',
35 | 'GET /storage/vol0/file.txt',
36 | 'GET /storage/vol0/file.txt',
37 | 'GET /storage/vol0/file.txt',
38 | 'GET /storage/vol0/file.txt'
39 | ]
40 | --- error_code eval
41 | [
42 | 200,
43 | 200,
44 | 200,
45 | 200,
46 | 200,
47 | 200
48 | ]
49 | --- response_body_like eval
50 | [
51 | 'OK',
52 | 'OK',
53 | 'OK',
54 | 'OK',
55 | 'OK',
56 | 'OK'
57 | ]
58 |
59 |
60 |
61 | === TEST 2: limit_check_duplicate off
62 | --- http_config
63 | vhost_traffic_status_zone;
64 | --- config
65 | error_page 503 /storage/limit/503.txt;
66 | location = /storage/limit/503.txt {
67 | internal;
68 | }
69 | location ~ ^/storage/(.+)/.*$ {
70 | set $volume $1;
71 | vhost_traffic_status_limit_check_duplicate off;
72 | vhost_traffic_status_filter_by_set_key $volume storage::$server_name;
73 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:8;
74 | vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:4;
75 | }
76 | --- user_files eval
77 | [
78 | ['storage/vol0/file.txt' => 'vol0:OK'],
79 | ['storage/limit/503.txt' => 'limited:OK']
80 | ]
81 | --- request eval
82 | [
83 | 'GET /storage/vol0/file.txt',
84 | 'GET /storage/vol0/file.txt',
85 | 'GET /storage/vol0/file.txt',
86 | 'GET /storage/vol0/file.txt',
87 | 'GET /storage/vol0/file.txt',
88 | 'GET /storage/vol0/file.txt'
89 | ]
90 | --- error_code eval
91 | [
92 | 200,
93 | 200,
94 | 200,
95 | 200,
96 | 200,
97 | 503
98 | ]
99 | --- response_body_like eval
100 | [
101 | 'OK',
102 | 'OK',
103 | 'OK',
104 | 'OK',
105 | 'OK',
106 | 'OK'
107 | ]
108 |
--------------------------------------------------------------------------------
/t/020.display_sum_key.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | plan tests => repeat_each() * blocks() * 2;
6 | no_shuffle();
7 | run_tests();
8 |
9 | __DATA__
10 |
11 | === TEST 1: display_sum_key total
12 | --- http_config
13 | vhost_traffic_status_zone;
14 | --- config
15 | location /status {
16 | vhost_traffic_status_display;
17 | vhost_traffic_status_display_sum_key total;
18 | vhost_traffic_status_display_format json;
19 | access_log off;
20 | }
21 | --- request eval
22 | [
23 | 'GET /status/format/json',
24 | ]
25 | --- response_body_like eval
26 | [
27 | 'total',
28 | ]
29 |
--------------------------------------------------------------------------------
/t/021.set_by_filter.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 | use Fcntl;
5 |
6 | add_response_body_check(
7 | sub {
8 | my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_;
9 |
10 | my $path = 't/servroot/logs/access.log';
11 | my @lines = FH->getlines() if (sysopen(FH, $path, O_RDONLY));
12 | close(FH);
13 | my $ll = $lines[-1];
14 |
15 | ($ll =~ /(requestCounter|inBytes|outBytes|2xx):[-0-9]/) or
16 | bail_out "variables by set_by_filter error($ll)";
17 |
18 | ($req_idx > 1 && $ll !~ /(requestCounter|2xx):[1-9]/) and
19 | bail_out "variables by set_by_filter error($ll)";
20 |
21 | if ($block->name =~ /TEST 5/) {
22 | ($req_idx > 1 && $ll !~ /(cacheMaxSize|cacheUsedSize|cacheHit):[0-9]/) and
23 | bail_out "variables by set_by_filter error($ll)";
24 | }
25 | }
26 | );
27 |
28 | add_cleanup_handler(
29 | sub {
30 | my $CacheDir = "t/servroot/cache_*";
31 | system("rm -rf $CacheDir > /dev/null") == 0 or
32 | bail_out "Can't remove $CacheDir";
33 | }
34 | );
35 |
36 |
37 | plan tests => repeat_each() * blocks() * 6;
38 | no_shuffle();
39 | run_tests();
40 |
41 | __DATA__
42 |
43 | === TEST 1: access variables by vhost_traffic_status_set_by_filter $* server/*/*
44 | --- http_config
45 | vhost_traffic_status_zone;
46 | log_format basic '[$time_local] requestCounter:$requestCounter '
47 | 'inBytes:$inBytes outBytes:$outBytes '
48 | '2xx:$2xx';
49 | access_log logs/access.log basic;
50 | --- config
51 | location /v {
52 | set $group server;
53 | set $zone localhost;
54 |
55 | vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter;
56 | vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes;
57 | vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes;
58 | vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx;
59 | }
60 | --- user_files eval
61 | [
62 | ['v/file.txt' => '{"return":"OK"}']
63 | ]
64 | --- request eval
65 | [
66 | 'GET /v/file.txt',
67 | 'GET /v/file.txt',
68 | 'GET /v/file.txt'
69 | ]
70 | --- response_body_like eval
71 | [
72 | 'OK',
73 | 'OK',
74 | 'OK'
75 | ]
76 |
77 |
78 |
79 | === TEST 2: access variables by vhost_traffic_status_set_by_filter $* upstream@alone/*/*
80 | --- http_config
81 | vhost_traffic_status_zone;
82 | log_format basic '[$time_local] requestCounter:$requestCounter '
83 | 'inBytes:$inBytes outBytes:$outBytes '
84 | '2xx:$2xx';
85 | access_log logs/access.log basic;
86 | upstream backend {
87 | server 127.0.0.1:1984;
88 | }
89 | --- config
90 | location /status {
91 | vhost_traffic_status_display;
92 | vhost_traffic_status_display_format json;
93 | access_log off;
94 | }
95 | location /v {
96 | set $group upstream@alone;
97 | set $zone 127.0.0.1:1984;
98 |
99 | vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter;
100 | vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes;
101 | vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes;
102 | vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx;
103 |
104 | proxy_pass http://127.0.0.1:1984/return;
105 | }
106 | --- user_files eval
107 | [
108 | ['return/file.txt' => '{"return":"OK"}']
109 | ]
110 | --- request eval
111 | [
112 | 'GET /v/file.txt',
113 | 'GET /v/file.txt',
114 | 'GET /v/file.txt'
115 | ]
116 | --- response_body_like eval
117 | [
118 | 'OK',
119 | 'OK',
120 | 'OK'
121 | ]
122 |
123 |
124 |
125 | === TEST 3: access variables by vhost_traffic_status_set_by_filter $* upstream@group/*/*
126 | --- http_config
127 | vhost_traffic_status_zone;
128 | log_format basic '[$time_local] requestCounter:$requestCounter '
129 | 'inBytes:$inBytes outBytes:$outBytes '
130 | '2xx:$2xx';
131 | access_log logs/access.log basic;
132 | upstream backend {
133 | server 127.0.0.1:1984;
134 | }
135 | --- config
136 | location /v {
137 | set $group upstream@group;
138 | set $zone backend@127.0.0.1:1984;
139 |
140 | vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter;
141 | vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes;
142 | vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes;
143 | vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx;
144 |
145 | proxy_pass http://backend/return;
146 | }
147 | --- user_files eval
148 | [
149 | ['return/file.txt' => '{"return":"OK"}']
150 | ]
151 | --- request eval
152 | [
153 | 'GET /v/file.txt',
154 | 'GET /v/file.txt',
155 | 'GET /v/file.txt'
156 | ]
157 | --- response_body_like eval
158 | [
159 | 'OK',
160 | 'OK',
161 | 'OK'
162 | ]
163 |
164 |
165 |
166 | === TEST 4: access variables by vhost_traffic_status_set_by_filter $* filter/*/*
167 | --- http_config
168 | vhost_traffic_status_zone;
169 | log_format basic '[$time_local] requestCounter:$requestCounter '
170 | 'inBytes:$inBytes outBytes:$outBytes '
171 | '2xx:$2xx';
172 | access_log logs/access.log basic;
173 | --- config
174 | location /v {
175 | vhost_traffic_status_filter_by_set_key v group;
176 |
177 | set $group filter;
178 | set $zone group@v;
179 |
180 | vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter;
181 | vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes;
182 | vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes;
183 | vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx;
184 | }
185 | --- user_files eval
186 | [
187 | ['v/file.txt' => '{"return":"OK"}']
188 | ]
189 | --- request eval
190 | [
191 | 'GET /v/file.txt',
192 | 'GET /v/file.txt',
193 | 'GET /v/file.txt'
194 | ]
195 | --- response_body_like eval
196 | [
197 | 'OK',
198 | 'OK',
199 | 'OK'
200 | ]
201 |
202 |
203 |
204 | === TEST 5: access variables by vhost_traffic_status_set_by_filter $* cache/*/*
205 | --- http_config
206 | vhost_traffic_status_zone;
207 | proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m;
208 | log_format basic '[$time_local] requestCounter:$requestCounter '
209 | 'inBytes:$inBytes outBytes:$outBytes '
210 | '2xx:$2xx cacheMaxSize:$cacheMaxSize '
211 | 'cacheUsedSize:$cacheUsedSize cacheHit:$cacheHit';
212 | access_log logs/access.log basic;
213 | upstream backend {
214 | server 127.0.0.1:1984;
215 | }
216 | --- config
217 | location /v {
218 | proxy_cache cache_one;
219 | proxy_cache_valid 200 10s;
220 |
221 | set $group cache;
222 | set $zone cache_one;
223 |
224 | vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter;
225 | vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes;
226 | vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes;
227 | vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx;
228 |
229 | vhost_traffic_status_set_by_filter $cacheMaxSize $group/$zone/cacheMaxSize;
230 | vhost_traffic_status_set_by_filter $cacheUsedSize $group/$zone/cacheUsedSize;
231 | vhost_traffic_status_set_by_filter $cacheHit $group/$zone/cacheHit;
232 |
233 | proxy_pass http://backend/return;
234 | }
235 | --- user_files eval
236 | [
237 | ['return/file.txt' => '{"return":"OK"}']
238 | ]
239 | --- request eval
240 | [
241 | 'GET /v/file.txt',
242 | 'GET /v/file.txt',
243 | 'GET /v/file.txt'
244 | ]
245 | --- response_body_like eval
246 | [
247 | 'OK',
248 | 'OK',
249 | 'OK'
250 | ]
251 |
--------------------------------------------------------------------------------
/t/022.display_prometheus.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | add_response_body_check(
6 | sub {
7 | my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_;
8 | system("echo '$body' | promtool check metrics") == 0 or
9 | bail_out "prometheus Syntax error($body)";
10 | }
11 | );
12 |
13 | plan tests => repeat_each(2) * blocks() * 3;
14 | no_shuffle();
15 | run_tests();
16 |
17 | __DATA__
18 |
19 | === TEST 1: /status/format/prometheus
20 | --- http_config
21 | vhost_traffic_status_zone;
22 | --- config
23 | location /status {
24 | vhost_traffic_status_display;
25 | vhost_traffic_status_display_format prometheus;
26 | }
27 | --- request
28 | GET /status/format/prometheus
29 | --- response_headers_like
30 | Content-Type: text/plain
31 | --- response_body_like eval
32 | [
33 | 'nginx_vts_info',
34 | ]
35 |
36 |
37 |
38 | === TEST 2: /status
39 | --- http_config
40 | vhost_traffic_status_zone;
41 | --- config
42 | location /status {
43 | vhost_traffic_status_display;
44 | vhost_traffic_status_display_format prometheus;
45 | }
46 | --- request
47 | GET /status
48 | --- response_headers_like
49 | Content-Type: text/plain
50 | --- response_body_like eval
51 | [
52 | 'nginx_vts_info',
53 | ]
54 |
--------------------------------------------------------------------------------
/t/023.histogram_buckets.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 | use Fcntl;
5 |
6 | plan tests => repeat_each() * blocks() * 4;
7 | no_shuffle();
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: access status with vhost_traffic_status_histogram_bucket to get the request and responseBuckets after accessing upstream backend
13 | --- http_config
14 | vhost_traffic_status_zone;
15 | vhost_traffic_status_histogram_buckets .1 .5 1 2;
16 | upstream backend {
17 | server 127.0.0.1;
18 | }
19 | server {
20 | server_name _;
21 | vhost_traffic_status_filter_by_host on;
22 | }
23 | --- config
24 | location /status {
25 | vhost_traffic_status_display;
26 | vhost_traffic_status_display_format json;
27 | access_log off;
28 | }
29 | location /one {
30 | proxy_set_header Host one.example.org;
31 | proxy_pass http://backend;
32 | }
33 | --- user_files eval
34 | [
35 | ['one/file.txt' => 'one.example.org:OK'],
36 | ]
37 | --- request eval
38 | [
39 | 'GET /one/file.txt',
40 | 'GET /status/',
41 | ]
42 | --- response_body_like eval
43 | [
44 | 'OK',
45 | '\"requestBuckets\"\:\{\"msecs\"\:\[100,500,1000,2000\],\"counters\"\:\[1,1,1,1\].*\"responseBuckets\"\:\{\"msecs\"\:\[100,500,1000,2000\],\"counters\"\:\[1,1,1,1\]',
46 | ]
47 |
--------------------------------------------------------------------------------
/t/024.upstream_check.t:
--------------------------------------------------------------------------------
1 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
2 |
3 | use Test::Nginx::Socket;
4 |
5 | master_on;
6 | plan skip_all => 'nginx_upstream_check test skipped' unless $ENV{TEST_UPSTREAM_CHECK};
7 | plan tests => 4;
8 | no_shuffle();
9 | run_tests();
10 |
11 | __DATA__
12 |
13 | === TEST 1: upstream peer->down is true
14 | --- http_config
15 | vhost_traffic_status_zone;
16 | upstream backend {
17 | zone backend 64k;
18 | server localhost:8080;
19 | check interval=1000 rise=1 fall=1 timeout=1000;
20 | }
21 | --- config
22 | location /backend {
23 | proxy_pass http://backend;
24 | }
25 | location /status {
26 | check_status;
27 | vhost_traffic_status_display;
28 | vhost_traffic_status_display_format json;
29 | access_log off;
30 | }
31 | --- request
32 | GET /status
33 | --- response_body_like eval
34 | '"down":true'
35 |
36 | === TEST 2: upstream peer->down is false
37 | --- http_config
38 | vhost_traffic_status_zone;
39 | upstream backend {
40 | zone backend 64k;
41 | server localhost:8080;
42 | check interval=1000 rise=1 fall=1 timeout=1000;
43 | }
44 | server {
45 | listen 8080;
46 | server_name localhost;
47 | location / {
48 | root html;
49 | }
50 | }
51 | --- config
52 | location /index.html {
53 | proxy_pass http://backend;
54 | }
55 | location /status {
56 | check_status;
57 | vhost_traffic_status_display;
58 | vhost_traffic_status_display_format json;
59 | access_log off;
60 | }
61 | --- request
62 | GET /status
63 | --- response_body_like eval
64 | '"down":false'
65 |
--------------------------------------------------------------------------------
/util/fileToHex.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | #
3 | # @file: fileToHex.pl
4 | # @brief:
5 | # @author: YoungJoo.Kim
6 | # @version:
7 | # @date:
8 |
9 | package FileToHex;
10 |
11 | use strict;
12 | use Carp;
13 |
14 | sub new{
15 | my($class, %cnf) = @_;
16 |
17 | my $path = delete $cnf{path};
18 | my $handle = delete $cnf{handle};
19 |
20 | my $self =
21 | bless {
22 | path => $path,
23 | handle => $handle
24 | }, $class;
25 |
26 | return bless $self;
27 | }
28 |
29 | sub __exit {
30 | my $self = shift if ref ($_[0]);
31 | my $res = shift;
32 | Carp::carp __PACKAGE__ . ": $res->{string}";
33 | exit($res->{return} || 1);
34 | }
35 |
36 | sub fileOpen {
37 | my $self = shift if ref ($_[0]);
38 | my $path = shift || $self->{path};
39 | $path = $self->{path} unless defined $path;
40 | (defined $path && -e $path) || $self->__exit({string => "error: [$path] is not defined or exists!"});
41 | open(my $handle, "<", $path) || $self->__exit({string => "error: open(): $!"});
42 | $self->{handle} = $handle;
43 | return $self->{handle};
44 | }
45 |
46 | sub fileClose {
47 | my $self = shift if ref ($_[0]);
48 | my $handle = shift || $self->{handle};
49 | $handle && close($handle);
50 | }
51 |
52 | sub fileReadByte {
53 | my $self = shift if ref ($_[0]);
54 | my $buf = \shift;
55 | my $byte = shift || 1;
56 | my $handle = shift || $self->{handle};
57 | return read($handle, $$buf, $byte);
58 | }
59 |
60 | sub DESTROY {
61 | my $self = shift if ref ($_[0]);
62 | $self->fileClose();
63 | }
64 |
65 | 1;
66 |
67 | package main;
68 |
69 | if ($#ARGV < 0) {
70 | print "Usage: $0 {path} {max} {type}\n";
71 | exit(2);
72 | }
73 |
74 | my $path = $ARGV[0];
75 | my $max = $ARGV[1] || 16;
76 | my $type = $ARGV[2] || "buffer";
77 | my $plus = "";
78 | my $buf = "";
79 | my $i = 0;
80 | my $fth = FileToHex->new(path => $path);
81 |
82 | $fth->fileOpen();
83 | if ($type eq "define") {
84 | # type: define
85 | while($fth->fileReadByte(my $c)) {
86 | $i++;
87 | $buf .= '\x' . unpack("H2", $c);
88 | if (!($i % $max)) {
89 | $plus .= "\"$buf\" \\\n";
90 | $buf = "";
91 | }
92 | }
93 |
94 | if (!($i % $max)) {
95 | print substr($plus, 0, -3) . "\n";
96 |
97 | } else {
98 | print $plus . "\"$buf\"\n";
99 | }
100 |
101 | } else {
102 | # type: buffer
103 | while($fth->fileReadByte(my $c)) {
104 | $i++;
105 | $buf .= '0x' . unpack("H2", $c) . ', ';
106 | if (!($i % $max)) {
107 | $plus .= "$buf\n";
108 | $buf = "";
109 | }
110 | }
111 |
112 | if (!($i % $max)) {
113 | print $plus . "0x00\n";
114 |
115 | } else {
116 | print $plus . $buf . "0x00\n";
117 | }
118 | }
119 | $fth->fileClose();
120 |
121 | # vi:set ft=perl ts=4 sw=4 et fdm=marker:
122 |
--------------------------------------------------------------------------------
/util/tplToBuffer.sh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 | #
3 | # @file: tplToDefine.sh
4 | # @brief:
5 | # @author: YoungJoo.Kim
6 | # @version:
7 | # @date:
8 |
9 | # Set up a default search path.
10 | PATH="/sbin:/usr/sbin:/bin:/usr/bin"
11 | export PATH
12 |
13 | template=$1
14 | if [ -z "$template" ]; then
15 | echo "Usage: $0 {template.html}"
16 | exit 2
17 | fi
18 |
19 | tmp=$template.$(date '+%s')
20 |
21 | \cp -af $template $tmp
22 |
23 | if [ -f "$tmp" ]; then
24 | perl -p -i -e 's/%/%%/g' $tmp
25 | perl -p -i -e 's/{{uri}}/%V/g' $tmp
26 | fi
27 |
28 | echo "static char NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA[] = {"
29 |
30 | \perl fileToHex.pl $tmp 16 buffer
31 |
32 | echo "};"
33 |
34 | \rm -f $tmp
35 |
36 | # vi:set ft=sh ts=4 sw=4 et fdm=marker:
37 |
--------------------------------------------------------------------------------
/util/tplToDefine.sh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 | #
3 | # @file: tplToDefine.sh
4 | # @brief:
5 | # @author: YoungJoo.Kim
6 | # @version:
7 | # @date:
8 |
9 | # Set up a default search path.
10 | PATH="/sbin:/usr/sbin:/bin:/usr/bin"
11 | export PATH
12 |
13 | template=$1
14 | if [ -z "$template" ]; then
15 | echo "Usage: $0 {template.html}"
16 | exit 2
17 | fi
18 |
19 | tmp=$template.$(date '+%s')
20 |
21 | \cp -af $template $tmp
22 |
23 | if [ -f "$tmp" ]; then
24 | perl -p -i -e 's/%/%%/g' $tmp
25 | perl -p -i -e 's/{{uri}}/%V/g' $tmp
26 | fi
27 |
28 | echo "#define NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA \\"
29 |
30 | \perl fileToHex.pl $tmp 16 define
31 |
32 | \rm -f $tmp
33 |
34 | # vi:set ft=sh ts=4 sw=4 et fdm=marker:
35 |
--------------------------------------------------------------------------------