├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── __init__.py
├── config
└── apache_gen.json
├── docs
├── .nojekyll
├── Makefile
├── index.html
├── lunaticlog
│ └── html
│ │ ├── .buildinfo
│ │ ├── .nojekyll
│ │ ├── _static
│ │ ├── ajax-loader.gif
│ │ ├── basic.css
│ │ ├── comment-bright.png
│ │ ├── comment-close.png
│ │ ├── comment.png
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ └── theme.css
│ │ ├── doctools.js
│ │ ├── down-pressed.png
│ │ ├── down.png
│ │ ├── file.png
│ │ ├── fonts
│ │ │ ├── Inconsolata-Bold.ttf
│ │ │ ├── Inconsolata-Regular.ttf
│ │ │ ├── Lato-Bold.ttf
│ │ │ ├── Lato-Regular.ttf
│ │ │ ├── RobotoSlab-Bold.ttf
│ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ └── fontawesome-webfont.woff
│ │ ├── jquery-3.1.0.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── modernizr.min.js
│ │ │ └── theme.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.3.1.js
│ │ ├── underscore.js
│ │ ├── up-pressed.png
│ │ ├── up.png
│ │ └── websupport.js
│ │ ├── contact.html
│ │ ├── genindex.html
│ │ ├── index.html
│ │ ├── installation.html
│ │ ├── license.html
│ │ ├── objects.inv
│ │ ├── quickstart.html
│ │ ├── search.html
│ │ └── searchindex.js
└── source
│ ├── conf.py
│ ├── contact.rst
│ ├── index.rst
│ ├── installation.rst
│ ├── license.rst
│ └── quickstart.rst
├── img
├── mode_push.png
├── mode_spike.png
└── mode_uniform.png
├── requirements.txt
├── scripts
└── bandwidth.py
├── setup.cfg
├── setup.py
├── src
├── __init__.py
├── apache_generator.py
└── base_generator.py
└── tests
├── __init__.py
└── log_generator_test.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Docs
2 | docs/lunaticlog/doctrees/
3 |
4 | # Testing log
5 | /tests/log/
6 | *.txt
7 | *.txt.*
8 |
9 | # Virtualenv
10 | lunatic/
11 |
12 | # Byte-compiled / optimized / DLL files
13 | __pycache__/
14 | *.py[cod]
15 | *$py.class
16 |
17 | # C extensions
18 | *.so
19 |
20 | # Distribution / packaging
21 | .Python
22 | env/
23 | #build/
24 | develop-eggs/
25 | dist/
26 | downloads/
27 | eggs/
28 | .eggs/
29 | lib/
30 | lib64/
31 | parts/
32 | sdist/
33 | var/
34 | *.egg-info/
35 | .installed.cfg
36 | *.egg
37 |
38 | # PyInstaller
39 | # Usually these files are written by a python script from a template
40 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
41 | *.manifest
42 | *.spec
43 |
44 | # Installer logs
45 | pip-log.txt
46 | pip-delete-this-directory.txt
47 |
48 | # Unit test / coverage reports
49 | htmlcov/
50 | .tox/
51 | .coverage
52 | .coverage.*
53 | .cache
54 | nosetests.xml
55 | coverage.xml
56 | *,cover
57 | .hypothesis/
58 |
59 | # Translations
60 | *.mo
61 | *.pot
62 |
63 | # Django stuff:
64 | *.log
65 | local_settings.py
66 |
67 | # Flask stuff:
68 | instance/
69 | .webassets-cache
70 |
71 | # Scrapy stuff:
72 | .scrapy
73 |
74 | # Sphinx documentation
75 | #docs/_build/
76 |
77 | # PyBuilder
78 | target/
79 |
80 | # IPython Notebook
81 | .ipynb_checkpoints
82 |
83 | # pyenv
84 | .python-version
85 |
86 | # celery beat schedule file
87 | celerybeat-schedule
88 |
89 | # dotenv
90 | .env
91 |
92 | # virtualenv
93 | venv/
94 | ENV/
95 |
96 | # Spyder project settings
97 | .spyderproject
98 |
99 | # Rope project settings
100 | .ropeproject
101 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "3.4"
4 | - "3.5"
5 | - "3.6"
6 | install:
7 | - "pip install -r requirements.txt"
8 | - "pip install coveralls"
9 | script:
10 | - coverage run --source src setup.py test
11 | after_success:
12 | - coveralls
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 WenyiXu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/xuwenyihust/Visor)
2 | [](https://badge.fury.io/py/lunaticlog)
3 | [](https://travis-ci.org/xuwenyihust/lunaticlog)
4 | [](https://coveralls.io/github/xuwenyihust/lunaticlog?branch=master)
5 | [](http://isitmaintained.com/project/xuwenyihust/lunaticlog "Percentage of issues still open")
6 | [](https://github.com/xuwenyihust/Visor/blob/master/LICENSE)
7 |
8 |
9 | # Lunaticlog: Fake Log Generator - [Read The Docs](https://xuwenyihust.github.io/lunaticlog/lunaticlog/html/)
10 | Lunaticlog is a mock HTTP log generator package, use it's fake log workloads to test if your monitor / analyzer can survive various extreme conditions.
11 |
12 |
13 | ## Documentation
14 | Lunaticlog's documentation can be found on https://xuwenyihust.github.io/lunaticlog/lunaticlog/html/.
15 |
16 |
17 | ## Overview
18 | Lunaticlog can generate logs with customized contents. The log traffic can also be configured.
19 |
20 | ### Supported Log Format
21 | What kinds of log formats does it support now?
22 |
23 | * Apache Access Log
24 |
25 | `127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326`
26 |
27 | * [TODO] Nginx Access Log
28 |
29 | `123.65.150.10 - - [23/Aug/2010:03:50:59 +0000] "POST /wordpress3/wp-admin/admin-ajax.php HTTP/1.1" 200 2 "http://www.example.com/wordpress3/wp-admin/post-new.php" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.25 Safari/534.3"`
30 |
31 | * [TODO] Amazon S3 Log
32 |
33 | `79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be mybucket [06/Feb/2014:00:00:38 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be 3E57427F3EXAMPLE REST.GET.VERSIONING - "GET /mybucket?versioning HTTP/1.1" 200 - 113 - 7 - "-" "S3Console/0.4" -`
34 |
35 | ### Log Rotation
36 | Set attribute `rotation_size` to rotate logs when current log file achieves the max size.
37 |
38 | ### Log Generation Mode
39 | The fate of lunaticlog is to create chaos to test your system. So it needs to generate various extreme cases, such as sudden traffic spikes.
40 |
41 | What traffic modes are supported now?
42 |
43 | * **uniform**
44 |
45 | Generate logs at a random rate, which is uniformly distributed.
46 |
47 | * **push**
48 |
49 | Generate logs at highest speed(which can be configured).
50 |
51 | * **spike**
52 |
53 | Generate logs at sudden very high rates periodically.
54 |
55 |
56 |
57 | The scripts to plot these bandwidth charts can be found under `./scripts`.
58 |
59 | ### Output Formats
60 |
61 | * STDOUT
62 |
63 | * `.log` file
64 |
65 | * `.gz` file
66 |
67 |
68 | ## Install
69 |
70 | `pip install lunaticlog`
71 |
72 |
73 | ## Usage Example
74 |
75 | ### apache_gen Class
76 |
77 | **Instantiation**
78 |
79 | ```python
80 | from lunaticlog import apache_gen
81 |
82 | log_gen = apache_gen(out_path='./apache.log', mode='uniform', rotation=True)
83 | log_gen.run()
84 | ```
85 |
86 | **Arguments**
87 |
88 | * `out_path`: path of output logs
89 |
90 | * `out_format`: format of output logs
91 |
92 | * `mode`: log traffic mode
93 |
94 | ## License
95 | See the LICENSE file for license rights and limitations (MIT).
96 |
97 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | from .src import log_gen
2 | from .src import apache_gen
3 |
4 | def help():
5 | return 'lunaticlog: to help you generate fake log loads.'
6 |
--------------------------------------------------------------------------------
/config/apache_gen.json:
--------------------------------------------------------------------------------
1 | {
2 | "lines": ["heartbeat" ,"access"],
3 | "heartbeat_interval": 0.1,
4 | "access_interval": [0.1, 2],
5 | "user_id": ["frank", "james", "john", "robert", "michael", "william", "david", "richard", "charles", "joseph", "thomas"],
6 | "methods": ["GET", "POST", "PUT", "DELETE"],
7 | "methods_p": [0.7,0.1,0.1,0.1],
8 | "resource": "/apache_pb.gif",
9 | "version": "HTTP/1.0",
10 | "code": "200",
11 | "rotation_size": 10000
12 | }
13 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = lunaticlog
8 | SOURCEDIR = source
9 | BUILDDIR = lunaticlog
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: 119d962ff8b729371099cac49fa0639b
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/.nojekyll
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/ajax-loader.gif
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/basic.css:
--------------------------------------------------------------------------------
1 | /*
2 | * basic.css
3 | * ~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- basic theme.
6 | *
7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /* -- main layout ----------------------------------------------------------- */
13 |
14 | div.clearer {
15 | clear: both;
16 | }
17 |
18 | /* -- relbar ---------------------------------------------------------------- */
19 |
20 | div.related {
21 | width: 100%;
22 | font-size: 90%;
23 | }
24 |
25 | div.related h3 {
26 | display: none;
27 | }
28 |
29 | div.related ul {
30 | margin: 0;
31 | padding: 0 0 0 10px;
32 | list-style: none;
33 | }
34 |
35 | div.related li {
36 | display: inline;
37 | }
38 |
39 | div.related li.right {
40 | float: right;
41 | margin-right: 5px;
42 | }
43 |
44 | /* -- sidebar --------------------------------------------------------------- */
45 |
46 | div.sphinxsidebarwrapper {
47 | padding: 10px 5px 0 10px;
48 | }
49 |
50 | div.sphinxsidebar {
51 | float: left;
52 | width: 230px;
53 | margin-left: -100%;
54 | font-size: 90%;
55 | word-wrap: break-word;
56 | overflow-wrap : break-word;
57 | }
58 |
59 | div.sphinxsidebar ul {
60 | list-style: none;
61 | }
62 |
63 | div.sphinxsidebar ul ul,
64 | div.sphinxsidebar ul.want-points {
65 | margin-left: 20px;
66 | list-style: square;
67 | }
68 |
69 | div.sphinxsidebar ul ul {
70 | margin-top: 0;
71 | margin-bottom: 0;
72 | }
73 |
74 | div.sphinxsidebar form {
75 | margin-top: 10px;
76 | }
77 |
78 | div.sphinxsidebar input {
79 | border: 1px solid #98dbcc;
80 | font-family: sans-serif;
81 | font-size: 1em;
82 | }
83 |
84 | div.sphinxsidebar #searchbox input[type="text"] {
85 | width: 170px;
86 | }
87 |
88 | img {
89 | border: 0;
90 | max-width: 100%;
91 | }
92 |
93 | /* -- search page ----------------------------------------------------------- */
94 |
95 | ul.search {
96 | margin: 10px 0 0 20px;
97 | padding: 0;
98 | }
99 |
100 | ul.search li {
101 | padding: 5px 0 5px 20px;
102 | background-image: url(file.png);
103 | background-repeat: no-repeat;
104 | background-position: 0 7px;
105 | }
106 |
107 | ul.search li a {
108 | font-weight: bold;
109 | }
110 |
111 | ul.search li div.context {
112 | color: #888;
113 | margin: 2px 0 0 30px;
114 | text-align: left;
115 | }
116 |
117 | ul.keywordmatches li.goodmatch a {
118 | font-weight: bold;
119 | }
120 |
121 | /* -- index page ------------------------------------------------------------ */
122 |
123 | table.contentstable {
124 | width: 90%;
125 | margin-left: auto;
126 | margin-right: auto;
127 | }
128 |
129 | table.contentstable p.biglink {
130 | line-height: 150%;
131 | }
132 |
133 | a.biglink {
134 | font-size: 1.3em;
135 | }
136 |
137 | span.linkdescr {
138 | font-style: italic;
139 | padding-top: 5px;
140 | font-size: 90%;
141 | }
142 |
143 | /* -- general index --------------------------------------------------------- */
144 |
145 | table.indextable {
146 | width: 100%;
147 | }
148 |
149 | table.indextable td {
150 | text-align: left;
151 | vertical-align: top;
152 | }
153 |
154 | table.indextable ul {
155 | margin-top: 0;
156 | margin-bottom: 0;
157 | list-style-type: none;
158 | }
159 |
160 | table.indextable > tbody > tr > td > ul {
161 | padding-left: 0em;
162 | }
163 |
164 | table.indextable tr.pcap {
165 | height: 10px;
166 | }
167 |
168 | table.indextable tr.cap {
169 | margin-top: 10px;
170 | background-color: #f2f2f2;
171 | }
172 |
173 | img.toggler {
174 | margin-right: 3px;
175 | margin-top: 3px;
176 | cursor: pointer;
177 | }
178 |
179 | div.modindex-jumpbox {
180 | border-top: 1px solid #ddd;
181 | border-bottom: 1px solid #ddd;
182 | margin: 1em 0 1em 0;
183 | padding: 0.4em;
184 | }
185 |
186 | div.genindex-jumpbox {
187 | border-top: 1px solid #ddd;
188 | border-bottom: 1px solid #ddd;
189 | margin: 1em 0 1em 0;
190 | padding: 0.4em;
191 | }
192 |
193 | /* -- domain module index --------------------------------------------------- */
194 |
195 | table.modindextable td {
196 | padding: 2px;
197 | border-collapse: collapse;
198 | }
199 |
200 | /* -- general body styles --------------------------------------------------- */
201 |
202 | div.body p, div.body dd, div.body li, div.body blockquote {
203 | -moz-hyphens: auto;
204 | -ms-hyphens: auto;
205 | -webkit-hyphens: auto;
206 | hyphens: auto;
207 | }
208 |
209 | a.headerlink {
210 | visibility: hidden;
211 | }
212 |
213 | h1:hover > a.headerlink,
214 | h2:hover > a.headerlink,
215 | h3:hover > a.headerlink,
216 | h4:hover > a.headerlink,
217 | h5:hover > a.headerlink,
218 | h6:hover > a.headerlink,
219 | dt:hover > a.headerlink,
220 | caption:hover > a.headerlink,
221 | p.caption:hover > a.headerlink,
222 | div.code-block-caption:hover > a.headerlink {
223 | visibility: visible;
224 | }
225 |
226 | div.body p.caption {
227 | text-align: inherit;
228 | }
229 |
230 | div.body td {
231 | text-align: left;
232 | }
233 |
234 | .first {
235 | margin-top: 0 !important;
236 | }
237 |
238 | p.rubric {
239 | margin-top: 30px;
240 | font-weight: bold;
241 | }
242 |
243 | img.align-left, .figure.align-left, object.align-left {
244 | clear: left;
245 | float: left;
246 | margin-right: 1em;
247 | }
248 |
249 | img.align-right, .figure.align-right, object.align-right {
250 | clear: right;
251 | float: right;
252 | margin-left: 1em;
253 | }
254 |
255 | img.align-center, .figure.align-center, object.align-center {
256 | display: block;
257 | margin-left: auto;
258 | margin-right: auto;
259 | }
260 |
261 | .align-left {
262 | text-align: left;
263 | }
264 |
265 | .align-center {
266 | text-align: center;
267 | }
268 |
269 | .align-right {
270 | text-align: right;
271 | }
272 |
273 | /* -- sidebars -------------------------------------------------------------- */
274 |
275 | div.sidebar {
276 | margin: 0 0 0.5em 1em;
277 | border: 1px solid #ddb;
278 | padding: 7px 7px 0 7px;
279 | background-color: #ffe;
280 | width: 40%;
281 | float: right;
282 | }
283 |
284 | p.sidebar-title {
285 | font-weight: bold;
286 | }
287 |
288 | /* -- topics ---------------------------------------------------------------- */
289 |
290 | div.topic {
291 | border: 1px solid #ccc;
292 | padding: 7px 7px 0 7px;
293 | margin: 10px 0 10px 0;
294 | }
295 |
296 | p.topic-title {
297 | font-size: 1.1em;
298 | font-weight: bold;
299 | margin-top: 10px;
300 | }
301 |
302 | /* -- admonitions ----------------------------------------------------------- */
303 |
304 | div.admonition {
305 | margin-top: 10px;
306 | margin-bottom: 10px;
307 | padding: 7px;
308 | }
309 |
310 | div.admonition dt {
311 | font-weight: bold;
312 | }
313 |
314 | div.admonition dl {
315 | margin-bottom: 0;
316 | }
317 |
318 | p.admonition-title {
319 | margin: 0px 10px 5px 0px;
320 | font-weight: bold;
321 | }
322 |
323 | div.body p.centered {
324 | text-align: center;
325 | margin-top: 25px;
326 | }
327 |
328 | /* -- tables ---------------------------------------------------------------- */
329 |
330 | table.docutils {
331 | border: 0;
332 | border-collapse: collapse;
333 | }
334 |
335 | table caption span.caption-number {
336 | font-style: italic;
337 | }
338 |
339 | table caption span.caption-text {
340 | }
341 |
342 | table.docutils td, table.docutils th {
343 | padding: 1px 8px 1px 5px;
344 | border-top: 0;
345 | border-left: 0;
346 | border-right: 0;
347 | border-bottom: 1px solid #aaa;
348 | }
349 |
350 | table.footnote td, table.footnote th {
351 | border: 0 !important;
352 | }
353 |
354 | th {
355 | text-align: left;
356 | padding-right: 5px;
357 | }
358 |
359 | table.citation {
360 | border-left: solid 1px gray;
361 | margin-left: 1px;
362 | }
363 |
364 | table.citation td {
365 | border-bottom: none;
366 | }
367 |
368 | /* -- figures --------------------------------------------------------------- */
369 |
370 | div.figure {
371 | margin: 0.5em;
372 | padding: 0.5em;
373 | }
374 |
375 | div.figure p.caption {
376 | padding: 0.3em;
377 | }
378 |
379 | div.figure p.caption span.caption-number {
380 | font-style: italic;
381 | }
382 |
383 | div.figure p.caption span.caption-text {
384 | }
385 |
386 | /* -- field list styles ----------------------------------------------------- */
387 |
388 | table.field-list td, table.field-list th {
389 | border: 0 !important;
390 | }
391 |
392 | .field-list ul {
393 | margin: 0;
394 | padding-left: 1em;
395 | }
396 |
397 | .field-list p {
398 | margin: 0;
399 | }
400 |
401 | .field-name {
402 | -moz-hyphens: manual;
403 | -ms-hyphens: manual;
404 | -webkit-hyphens: manual;
405 | hyphens: manual;
406 | }
407 |
408 | /* -- other body styles ----------------------------------------------------- */
409 |
410 | ol.arabic {
411 | list-style: decimal;
412 | }
413 |
414 | ol.loweralpha {
415 | list-style: lower-alpha;
416 | }
417 |
418 | ol.upperalpha {
419 | list-style: upper-alpha;
420 | }
421 |
422 | ol.lowerroman {
423 | list-style: lower-roman;
424 | }
425 |
426 | ol.upperroman {
427 | list-style: upper-roman;
428 | }
429 |
430 | dl {
431 | margin-bottom: 15px;
432 | }
433 |
434 | dd p {
435 | margin-top: 0px;
436 | }
437 |
438 | dd ul, dd table {
439 | margin-bottom: 10px;
440 | }
441 |
442 | dd {
443 | margin-top: 3px;
444 | margin-bottom: 10px;
445 | margin-left: 30px;
446 | }
447 |
448 | dt:target, .highlighted {
449 | background-color: #fbe54e;
450 | }
451 |
452 | dl.glossary dt {
453 | font-weight: bold;
454 | font-size: 1.1em;
455 | }
456 |
457 | .optional {
458 | font-size: 1.3em;
459 | }
460 |
461 | .sig-paren {
462 | font-size: larger;
463 | }
464 |
465 | .versionmodified {
466 | font-style: italic;
467 | }
468 |
469 | .system-message {
470 | background-color: #fda;
471 | padding: 5px;
472 | border: 3px solid red;
473 | }
474 |
475 | .footnote:target {
476 | background-color: #ffa;
477 | }
478 |
479 | .line-block {
480 | display: block;
481 | margin-top: 1em;
482 | margin-bottom: 1em;
483 | }
484 |
485 | .line-block .line-block {
486 | margin-top: 0;
487 | margin-bottom: 0;
488 | margin-left: 1.5em;
489 | }
490 |
491 | .guilabel, .menuselection {
492 | font-family: sans-serif;
493 | }
494 |
495 | .accelerator {
496 | text-decoration: underline;
497 | }
498 |
499 | .classifier {
500 | font-style: oblique;
501 | }
502 |
503 | abbr, acronym {
504 | border-bottom: dotted 1px;
505 | cursor: help;
506 | }
507 |
508 | /* -- code displays --------------------------------------------------------- */
509 |
510 | pre {
511 | overflow: auto;
512 | overflow-y: hidden; /* fixes display issues on Chrome browsers */
513 | }
514 |
515 | span.pre {
516 | -moz-hyphens: none;
517 | -ms-hyphens: none;
518 | -webkit-hyphens: none;
519 | hyphens: none;
520 | }
521 |
522 | td.linenos pre {
523 | padding: 5px 0px;
524 | border: 0;
525 | background-color: transparent;
526 | color: #aaa;
527 | }
528 |
529 | table.highlighttable {
530 | margin-left: 0.5em;
531 | }
532 |
533 | table.highlighttable td {
534 | padding: 0 0.5em 0 0.5em;
535 | }
536 |
537 | div.code-block-caption {
538 | padding: 2px 5px;
539 | font-size: small;
540 | }
541 |
542 | div.code-block-caption code {
543 | background-color: transparent;
544 | }
545 |
546 | div.code-block-caption + div > div.highlight > pre {
547 | margin-top: 0;
548 | }
549 |
550 | div.code-block-caption span.caption-number {
551 | padding: 0.1em 0.3em;
552 | font-style: italic;
553 | }
554 |
555 | div.code-block-caption span.caption-text {
556 | }
557 |
558 | div.literal-block-wrapper {
559 | padding: 1em 1em 0;
560 | }
561 |
562 | div.literal-block-wrapper div.highlight {
563 | margin: 0;
564 | }
565 |
566 | code.descname {
567 | background-color: transparent;
568 | font-weight: bold;
569 | font-size: 1.2em;
570 | }
571 |
572 | code.descclassname {
573 | background-color: transparent;
574 | }
575 |
576 | code.xref, a code {
577 | background-color: transparent;
578 | font-weight: bold;
579 | }
580 |
581 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
582 | background-color: transparent;
583 | }
584 |
585 | .viewcode-link {
586 | float: right;
587 | }
588 |
589 | .viewcode-back {
590 | float: right;
591 | font-family: sans-serif;
592 | }
593 |
594 | div.viewcode-block:target {
595 | margin: -1px -10px;
596 | padding: 0 10px;
597 | }
598 |
599 | /* -- math display ---------------------------------------------------------- */
600 |
601 | img.math {
602 | vertical-align: middle;
603 | }
604 |
605 | div.body div.math p {
606 | text-align: center;
607 | }
608 |
609 | span.eqno {
610 | float: right;
611 | }
612 |
613 | span.eqno a.headerlink {
614 | position: relative;
615 | left: 0px;
616 | z-index: 1;
617 | }
618 |
619 | div.math:hover a.headerlink {
620 | visibility: visible;
621 | }
622 |
623 | /* -- printout stylesheet --------------------------------------------------- */
624 |
625 | @media print {
626 | div.document,
627 | div.documentwrapper,
628 | div.bodywrapper {
629 | margin: 0 !important;
630 | width: 100%;
631 | }
632 |
633 | div.sphinxsidebar,
634 | div.related,
635 | div.footer,
636 | #top-link {
637 | display: none;
638 | }
639 | }
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/comment-bright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/comment-bright.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/comment-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/comment-close.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/comment.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
2 | /*# sourceMappingURL=badge_only.css.map */
3 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/doctools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * doctools.js
3 | * ~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 | /**
18 | * make the code below compatible with browsers without
19 | * an installed firebug like debugger
20 | if (!window.console || !console.firebug) {
21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 | "profile", "profileEnd"];
24 | window.console = {};
25 | for (var i = 0; i < names.length; ++i)
26 | window.console[names[i]] = function() {};
27 | }
28 | */
29 |
30 | /**
31 | * small helper function to urldecode strings
32 | */
33 | jQuery.urldecode = function(x) {
34 | return decodeURIComponent(x).replace(/\+/g, ' ');
35 | };
36 |
37 | /**
38 | * small helper function to urlencode strings
39 | */
40 | jQuery.urlencode = encodeURIComponent;
41 |
42 | /**
43 | * This function returns the parsed url parameters of the
44 | * current request. Multiple values per key are supported,
45 | * it will always return arrays of strings for the value parts.
46 | */
47 | jQuery.getQueryParameters = function(s) {
48 | if (typeof s == 'undefined')
49 | s = document.location.search;
50 | var parts = s.substr(s.indexOf('?') + 1).split('&');
51 | var result = {};
52 | for (var i = 0; i < parts.length; i++) {
53 | var tmp = parts[i].split('=', 2);
54 | var key = jQuery.urldecode(tmp[0]);
55 | var value = jQuery.urldecode(tmp[1]);
56 | if (key in result)
57 | result[key].push(value);
58 | else
59 | result[key] = [value];
60 | }
61 | return result;
62 | };
63 |
64 | /**
65 | * highlight a given string on a jquery object by wrapping it in
66 | * span elements with the given class name.
67 | */
68 | jQuery.fn.highlightText = function(text, className) {
69 | function highlight(node) {
70 | if (node.nodeType == 3) {
71 | var val = node.nodeValue;
72 | var pos = val.toLowerCase().indexOf(text);
73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
74 | var span = document.createElement("span");
75 | span.className = className;
76 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
78 | document.createTextNode(val.substr(pos + text.length)),
79 | node.nextSibling));
80 | node.nodeValue = val.substr(0, pos);
81 | }
82 | }
83 | else if (!jQuery(node).is("button, select, textarea")) {
84 | jQuery.each(node.childNodes, function() {
85 | highlight(this);
86 | });
87 | }
88 | }
89 | return this.each(function() {
90 | highlight(this);
91 | });
92 | };
93 |
94 | /*
95 | * backward compatibility for jQuery.browser
96 | * This will be supported until firefox bug is fixed.
97 | */
98 | if (!jQuery.browser) {
99 | jQuery.uaMatch = function(ua) {
100 | ua = ua.toLowerCase();
101 |
102 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
103 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
104 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
105 | /(msie) ([\w.]+)/.exec(ua) ||
106 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
107 | [];
108 |
109 | return {
110 | browser: match[ 1 ] || "",
111 | version: match[ 2 ] || "0"
112 | };
113 | };
114 | jQuery.browser = {};
115 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
116 | }
117 |
118 | /**
119 | * Small JavaScript module for the documentation.
120 | */
121 | var Documentation = {
122 |
123 | init : function() {
124 | this.fixFirefoxAnchorBug();
125 | this.highlightSearchWords();
126 | this.initIndexTable();
127 |
128 | },
129 |
130 | /**
131 | * i18n support
132 | */
133 | TRANSLATIONS : {},
134 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
135 | LOCALE : 'unknown',
136 |
137 | // gettext and ngettext don't access this so that the functions
138 | // can safely bound to a different name (_ = Documentation.gettext)
139 | gettext : function(string) {
140 | var translated = Documentation.TRANSLATIONS[string];
141 | if (typeof translated == 'undefined')
142 | return string;
143 | return (typeof translated == 'string') ? translated : translated[0];
144 | },
145 |
146 | ngettext : function(singular, plural, n) {
147 | var translated = Documentation.TRANSLATIONS[singular];
148 | if (typeof translated == 'undefined')
149 | return (n == 1) ? singular : plural;
150 | return translated[Documentation.PLURALEXPR(n)];
151 | },
152 |
153 | addTranslations : function(catalog) {
154 | for (var key in catalog.messages)
155 | this.TRANSLATIONS[key] = catalog.messages[key];
156 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
157 | this.LOCALE = catalog.locale;
158 | },
159 |
160 | /**
161 | * add context elements like header anchor links
162 | */
163 | addContextElements : function() {
164 | $('div[id] > :header:first').each(function() {
165 | $('').
166 | attr('href', '#' + this.id).
167 | attr('title', _('Permalink to this headline')).
168 | appendTo(this);
169 | });
170 | $('dt[id]').each(function() {
171 | $('').
172 | attr('href', '#' + this.id).
173 | attr('title', _('Permalink to this definition')).
174 | appendTo(this);
175 | });
176 | },
177 |
178 | /**
179 | * workaround a firefox stupidity
180 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
181 | */
182 | fixFirefoxAnchorBug : function() {
183 | if (document.location.hash)
184 | window.setTimeout(function() {
185 | document.location.href += '';
186 | }, 10);
187 | },
188 |
189 | /**
190 | * highlight the search words provided in the url in the text
191 | */
192 | highlightSearchWords : function() {
193 | var params = $.getQueryParameters();
194 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
195 | if (terms.length) {
196 | var body = $('div.body');
197 | if (!body.length) {
198 | body = $('body');
199 | }
200 | window.setTimeout(function() {
201 | $.each(terms, function() {
202 | body.highlightText(this.toLowerCase(), 'highlighted');
203 | });
204 | }, 10);
205 | $('
' + _('Hide Search Matches') + '
')
207 | .appendTo($('#searchbox'));
208 | }
209 | },
210 |
211 | /**
212 | * init the domain index toggle buttons
213 | */
214 | initIndexTable : function() {
215 | var togglers = $('img.toggler').click(function() {
216 | var src = $(this).attr('src');
217 | var idnum = $(this).attr('id').substr(7);
218 | $('tr.cg-' + idnum).toggle();
219 | if (src.substr(-9) == 'minus.png')
220 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
221 | else
222 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
223 | }).css('display', '');
224 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
225 | togglers.click();
226 | }
227 | },
228 |
229 | /**
230 | * helper function to hide the search marks again
231 | */
232 | hideSearchWords : function() {
233 | $('#searchbox .highlight-link').fadeOut(300);
234 | $('span.highlighted').removeClass('highlighted');
235 | },
236 |
237 | /**
238 | * make the url absolute
239 | */
240 | makeURL : function(relativeURL) {
241 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
242 | },
243 |
244 | /**
245 | * get the current relative url
246 | */
247 | getCurrentURL : function() {
248 | var path = document.location.pathname;
249 | var parts = path.split(/\//);
250 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
251 | if (this == '..')
252 | parts.pop();
253 | });
254 | var url = parts.join('/');
255 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
256 | },
257 |
258 | initOnKeyListeners: function() {
259 | $(document).keyup(function(event) {
260 | var activeElementType = document.activeElement.tagName;
261 | // don't navigate when in search box or textarea
262 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
263 | switch (event.keyCode) {
264 | case 37: // left
265 | var prevHref = $('link[rel="prev"]').prop('href');
266 | if (prevHref) {
267 | window.location.href = prevHref;
268 | return false;
269 | }
270 | case 39: // right
271 | var nextHref = $('link[rel="next"]').prop('href');
272 | if (nextHref) {
273 | window.location.href = nextHref;
274 | return false;
275 | }
276 | }
277 | }
278 | });
279 | }
280 | };
281 |
282 | // quick alias for translations
283 | _ = Documentation.gettext;
284 |
285 | $(document).ready(function() {
286 | Documentation.init();
287 | });
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/down-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/down-pressed.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/down.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/file.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/Inconsolata-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/Inconsolata-Bold.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/Inconsolata-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/Inconsolata-Regular.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/Lato-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/Lato-Bold.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/RobotoSlab-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/RobotoSlab-Bold.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/js/modernizr.min.js:
--------------------------------------------------------------------------------
1 | /* Modernizr 2.6.2 (Custom Build) | MIT & BSD
2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
3 | */
4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML=" ",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f");
80 |
81 | // Add expand links to all parents of nested ul
82 | $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () {
83 | var link = $(this);
84 | expand = $(' ');
85 | expand.on('click', function (ev) {
86 | self.toggleCurrent(link);
87 | ev.stopPropagation();
88 | return false;
89 | });
90 | link.prepend(expand);
91 | });
92 | };
93 |
94 | nav.reset = function () {
95 | // Get anchor from URL and open up nested nav
96 | var anchor = encodeURI(window.location.hash);
97 | if (anchor) {
98 | try {
99 | var link = $('.wy-menu-vertical')
100 | .find('[href="' + anchor + '"]');
101 | // If we didn't find a link, it may be because we clicked on
102 | // something that is not in the sidebar (eg: when using
103 | // sphinxcontrib.httpdomain it generates headerlinks but those
104 | // aren't picked up and placed in the toctree). So let's find
105 | // the closest header in the document and try with that one.
106 | if (link.length === 0) {
107 | var doc_link = $('.document a[href="' + anchor + '"]');
108 | var closest_section = doc_link.closest('div.section');
109 | // Try again with the closest section entry.
110 | link = $('.wy-menu-vertical')
111 | .find('[href="#' + closest_section.attr("id") + '"]');
112 |
113 | }
114 | $('.wy-menu-vertical li.toctree-l1 li.current')
115 | .removeClass('current');
116 | link.closest('li.toctree-l2').addClass('current');
117 | link.closest('li.toctree-l3').addClass('current');
118 | link.closest('li.toctree-l4').addClass('current');
119 | }
120 | catch (err) {
121 | console.log("Error expanding nav for anchor", err);
122 | }
123 | }
124 | };
125 |
126 | nav.onScroll = function () {
127 | this.winScroll = false;
128 | var newWinPosition = this.win.scrollTop(),
129 | winBottom = newWinPosition + this.winHeight,
130 | navPosition = this.navBar.scrollTop(),
131 | newNavPosition = navPosition + (newWinPosition - this.winPosition);
132 | if (newWinPosition < 0 || winBottom > this.docHeight) {
133 | return;
134 | }
135 | this.navBar.scrollTop(newNavPosition);
136 | this.winPosition = newWinPosition;
137 | };
138 |
139 | nav.onResize = function () {
140 | this.winResize = false;
141 | this.winHeight = this.win.height();
142 | this.docHeight = $(document).height();
143 | };
144 |
145 | nav.hashChange = function () {
146 | this.linkScroll = true;
147 | this.win.one('hashchange', function () {
148 | this.linkScroll = false;
149 | });
150 | };
151 |
152 | nav.toggleCurrent = function (elem) {
153 | var parent_li = elem.closest('li');
154 | parent_li.siblings('li.current').removeClass('current');
155 | parent_li.siblings().find('li.current').removeClass('current');
156 | parent_li.find('> ul li.current').removeClass('current');
157 | parent_li.toggleClass('current');
158 | }
159 |
160 | return nav;
161 | };
162 |
163 | module.exports.ThemeNav = ThemeNav();
164 |
165 | if (typeof(window) != 'undefined') {
166 | window.SphinxRtdTheme = { StickyNav: module.exports.ThemeNav };
167 | }
168 |
169 | },{"jquery":"jquery"}]},{},["sphinx-rtd-theme"]);
170 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/minus.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/plus.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #eeffcc; }
3 | .highlight .c { color: #408090; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
9 | .highlight .cp { color: #007020 } /* Comment.Preproc */
10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
14 | .highlight .ge { font-style: italic } /* Generic.Emph */
15 | .highlight .gr { color: #FF0000 } /* Generic.Error */
16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
18 | .highlight .go { color: #333333 } /* Generic.Output */
19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
20 | .highlight .gs { font-weight: bold } /* Generic.Strong */
21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */
27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
28 | .highlight .kt { color: #902000 } /* Keyword.Type */
29 | .highlight .m { color: #208050 } /* Literal.Number */
30 | .highlight .s { color: #4070a0 } /* Literal.String */
31 | .highlight .na { color: #4070a0 } /* Name.Attribute */
32 | .highlight .nb { color: #007020 } /* Name.Builtin */
33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
34 | .highlight .no { color: #60add5 } /* Name.Constant */
35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
37 | .highlight .ne { color: #007020 } /* Name.Exception */
38 | .highlight .nf { color: #06287e } /* Name.Function */
39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */
43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */
46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */
47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */
48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */
49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */
50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */
51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */
53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */
56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */
60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */
61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */
62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */
63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */
65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/searchtools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * searchtools.js_t
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for the full-text search.
6 | *
7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 |
13 | /* Non-minified version JS is _stemmer.js if file is provided */
14 | /**
15 | * Porter Stemmer
16 | */
17 | var Stemmer = function() {
18 |
19 | var step2list = {
20 | ational: 'ate',
21 | tional: 'tion',
22 | enci: 'ence',
23 | anci: 'ance',
24 | izer: 'ize',
25 | bli: 'ble',
26 | alli: 'al',
27 | entli: 'ent',
28 | eli: 'e',
29 | ousli: 'ous',
30 | ization: 'ize',
31 | ation: 'ate',
32 | ator: 'ate',
33 | alism: 'al',
34 | iveness: 'ive',
35 | fulness: 'ful',
36 | ousness: 'ous',
37 | aliti: 'al',
38 | iviti: 'ive',
39 | biliti: 'ble',
40 | logi: 'log'
41 | };
42 |
43 | var step3list = {
44 | icate: 'ic',
45 | ative: '',
46 | alize: 'al',
47 | iciti: 'ic',
48 | ical: 'ic',
49 | ful: '',
50 | ness: ''
51 | };
52 |
53 | var c = "[^aeiou]"; // consonant
54 | var v = "[aeiouy]"; // vowel
55 | var C = c + "[^aeiouy]*"; // consonant sequence
56 | var V = v + "[aeiou]*"; // vowel sequence
57 |
58 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
59 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
60 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
61 | var s_v = "^(" + C + ")?" + v; // vowel in stem
62 |
63 | this.stemWord = function (w) {
64 | var stem;
65 | var suffix;
66 | var firstch;
67 | var origword = w;
68 |
69 | if (w.length < 3)
70 | return w;
71 |
72 | var re;
73 | var re2;
74 | var re3;
75 | var re4;
76 |
77 | firstch = w.substr(0,1);
78 | if (firstch == "y")
79 | w = firstch.toUpperCase() + w.substr(1);
80 |
81 | // Step 1a
82 | re = /^(.+?)(ss|i)es$/;
83 | re2 = /^(.+?)([^s])s$/;
84 |
85 | if (re.test(w))
86 | w = w.replace(re,"$1$2");
87 | else if (re2.test(w))
88 | w = w.replace(re2,"$1$2");
89 |
90 | // Step 1b
91 | re = /^(.+?)eed$/;
92 | re2 = /^(.+?)(ed|ing)$/;
93 | if (re.test(w)) {
94 | var fp = re.exec(w);
95 | re = new RegExp(mgr0);
96 | if (re.test(fp[1])) {
97 | re = /.$/;
98 | w = w.replace(re,"");
99 | }
100 | }
101 | else if (re2.test(w)) {
102 | var fp = re2.exec(w);
103 | stem = fp[1];
104 | re2 = new RegExp(s_v);
105 | if (re2.test(stem)) {
106 | w = stem;
107 | re2 = /(at|bl|iz)$/;
108 | re3 = new RegExp("([^aeiouylsz])\\1$");
109 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
110 | if (re2.test(w))
111 | w = w + "e";
112 | else if (re3.test(w)) {
113 | re = /.$/;
114 | w = w.replace(re,"");
115 | }
116 | else if (re4.test(w))
117 | w = w + "e";
118 | }
119 | }
120 |
121 | // Step 1c
122 | re = /^(.+?)y$/;
123 | if (re.test(w)) {
124 | var fp = re.exec(w);
125 | stem = fp[1];
126 | re = new RegExp(s_v);
127 | if (re.test(stem))
128 | w = stem + "i";
129 | }
130 |
131 | // Step 2
132 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
133 | if (re.test(w)) {
134 | var fp = re.exec(w);
135 | stem = fp[1];
136 | suffix = fp[2];
137 | re = new RegExp(mgr0);
138 | if (re.test(stem))
139 | w = stem + step2list[suffix];
140 | }
141 |
142 | // Step 3
143 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
144 | if (re.test(w)) {
145 | var fp = re.exec(w);
146 | stem = fp[1];
147 | suffix = fp[2];
148 | re = new RegExp(mgr0);
149 | if (re.test(stem))
150 | w = stem + step3list[suffix];
151 | }
152 |
153 | // Step 4
154 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
155 | re2 = /^(.+?)(s|t)(ion)$/;
156 | if (re.test(w)) {
157 | var fp = re.exec(w);
158 | stem = fp[1];
159 | re = new RegExp(mgr1);
160 | if (re.test(stem))
161 | w = stem;
162 | }
163 | else if (re2.test(w)) {
164 | var fp = re2.exec(w);
165 | stem = fp[1] + fp[2];
166 | re2 = new RegExp(mgr1);
167 | if (re2.test(stem))
168 | w = stem;
169 | }
170 |
171 | // Step 5
172 | re = /^(.+?)e$/;
173 | if (re.test(w)) {
174 | var fp = re.exec(w);
175 | stem = fp[1];
176 | re = new RegExp(mgr1);
177 | re2 = new RegExp(meq1);
178 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
179 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
180 | w = stem;
181 | }
182 | re = /ll$/;
183 | re2 = new RegExp(mgr1);
184 | if (re.test(w) && re2.test(w)) {
185 | re = /.$/;
186 | w = w.replace(re,"");
187 | }
188 |
189 | // and turn initial Y back to y
190 | if (firstch == "y")
191 | w = firstch.toLowerCase() + w.substr(1);
192 | return w;
193 | }
194 | }
195 |
196 |
197 |
198 | /**
199 | * Simple result scoring code.
200 | */
201 | var Scorer = {
202 | // Implement the following function to further tweak the score for each result
203 | // The function takes a result array [filename, title, anchor, descr, score]
204 | // and returns the new score.
205 | /*
206 | score: function(result) {
207 | return result[4];
208 | },
209 | */
210 |
211 | // query matches the full name of an object
212 | objNameMatch: 11,
213 | // or matches in the last dotted part of the object name
214 | objPartialMatch: 6,
215 | // Additive scores depending on the priority of the object
216 | objPrio: {0: 15, // used to be importantResults
217 | 1: 5, // used to be objectResults
218 | 2: -5}, // used to be unimportantResults
219 | // Used when the priority is not in the mapping.
220 | objPrioDefault: 0,
221 |
222 | // query found in title
223 | title: 15,
224 | // query found in terms
225 | term: 5
226 | };
227 |
228 |
229 |
230 |
231 |
232 | var splitChars = (function() {
233 | var result = {};
234 | var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
235 | 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
236 | 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
237 | 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
238 | 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
239 | 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
240 | 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
241 | 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
242 | 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
243 | 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
244 | var i, j, start, end;
245 | for (i = 0; i < singles.length; i++) {
246 | result[singles[i]] = true;
247 | }
248 | var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
249 | [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
250 | [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
251 | [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
252 | [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
253 | [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
254 | [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
255 | [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
256 | [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
257 | [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
258 | [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
259 | [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
260 | [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
261 | [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
262 | [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
263 | [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
264 | [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
265 | [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
266 | [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
267 | [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
268 | [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
269 | [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
270 | [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
271 | [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
272 | [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
273 | [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
274 | [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
275 | [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
276 | [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
277 | [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
278 | [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
279 | [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
280 | [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
281 | [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
282 | [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
283 | [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
284 | [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
285 | [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
286 | [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
287 | [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
288 | [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
289 | [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
290 | [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
291 | [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
292 | [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
293 | [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
294 | [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
295 | [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
296 | [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
297 | for (i = 0; i < ranges.length; i++) {
298 | start = ranges[i][0];
299 | end = ranges[i][1];
300 | for (j = start; j <= end; j++) {
301 | result[j] = true;
302 | }
303 | }
304 | return result;
305 | })();
306 |
307 | function splitQuery(query) {
308 | var result = [];
309 | var start = -1;
310 | for (var i = 0; i < query.length; i++) {
311 | if (splitChars[query.charCodeAt(i)]) {
312 | if (start !== -1) {
313 | result.push(query.slice(start, i));
314 | start = -1;
315 | }
316 | } else if (start === -1) {
317 | start = i;
318 | }
319 | }
320 | if (start !== -1) {
321 | result.push(query.slice(start));
322 | }
323 | return result;
324 | }
325 |
326 |
327 |
328 |
329 | /**
330 | * Search Module
331 | */
332 | var Search = {
333 |
334 | _index : null,
335 | _queued_query : null,
336 | _pulse_status : -1,
337 |
338 | init : function() {
339 | var params = $.getQueryParameters();
340 | if (params.q) {
341 | var query = params.q[0];
342 | $('input[name="q"]')[0].value = query;
343 | this.performSearch(query);
344 | }
345 | },
346 |
347 | loadIndex : function(url) {
348 | $.ajax({type: "GET", url: url, data: null,
349 | dataType: "script", cache: true,
350 | complete: function(jqxhr, textstatus) {
351 | if (textstatus != "success") {
352 | document.getElementById("searchindexloader").src = url;
353 | }
354 | }});
355 | },
356 |
357 | setIndex : function(index) {
358 | var q;
359 | this._index = index;
360 | if ((q = this._queued_query) !== null) {
361 | this._queued_query = null;
362 | Search.query(q);
363 | }
364 | },
365 |
366 | hasIndex : function() {
367 | return this._index !== null;
368 | },
369 |
370 | deferQuery : function(query) {
371 | this._queued_query = query;
372 | },
373 |
374 | stopPulse : function() {
375 | this._pulse_status = 0;
376 | },
377 |
378 | startPulse : function() {
379 | if (this._pulse_status >= 0)
380 | return;
381 | function pulse() {
382 | var i;
383 | Search._pulse_status = (Search._pulse_status + 1) % 4;
384 | var dotString = '';
385 | for (i = 0; i < Search._pulse_status; i++)
386 | dotString += '.';
387 | Search.dots.text(dotString);
388 | if (Search._pulse_status > -1)
389 | window.setTimeout(pulse, 500);
390 | }
391 | pulse();
392 | },
393 |
394 | /**
395 | * perform a search for something (or wait until index is loaded)
396 | */
397 | performSearch : function(query) {
398 | // create the required interface elements
399 | this.out = $('#search-results');
400 | this.title = $('' + _('Searching') + ' ').appendTo(this.out);
401 | this.dots = $(' ').appendTo(this.title);
402 | this.status = $('
').appendTo(this.out);
403 | this.output = $('').appendTo(this.out);
404 |
405 | $('#search-progress').text(_('Preparing search...'));
406 | this.startPulse();
407 |
408 | // index already loaded, the browser was quick!
409 | if (this.hasIndex())
410 | this.query(query);
411 | else
412 | this.deferQuery(query);
413 | },
414 |
415 | /**
416 | * execute search (requires search index to be loaded)
417 | */
418 | query : function(query) {
419 | var i;
420 | var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
421 |
422 | // stem the searchterms and add them to the correct list
423 | var stemmer = new Stemmer();
424 | var searchterms = [];
425 | var excluded = [];
426 | var hlterms = [];
427 | var tmp = splitQuery(query);
428 | var objectterms = [];
429 | for (i = 0; i < tmp.length; i++) {
430 | if (tmp[i] !== "") {
431 | objectterms.push(tmp[i].toLowerCase());
432 | }
433 |
434 | if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
435 | tmp[i] === "") {
436 | // skip this "word"
437 | continue;
438 | }
439 | // stem the word
440 | var word = stemmer.stemWord(tmp[i].toLowerCase());
441 | // prevent stemmer from cutting word smaller than two chars
442 | if(word.length < 3 && tmp[i].length >= 3) {
443 | word = tmp[i];
444 | }
445 | var toAppend;
446 | // select the correct list
447 | if (word[0] == '-') {
448 | toAppend = excluded;
449 | word = word.substr(1);
450 | }
451 | else {
452 | toAppend = searchterms;
453 | hlterms.push(tmp[i].toLowerCase());
454 | }
455 | // only add if not already in the list
456 | if (!$u.contains(toAppend, word))
457 | toAppend.push(word);
458 | }
459 | var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
460 |
461 | // console.debug('SEARCH: searching for:');
462 | // console.info('required: ', searchterms);
463 | // console.info('excluded: ', excluded);
464 |
465 | // prepare search
466 | var terms = this._index.terms;
467 | var titleterms = this._index.titleterms;
468 |
469 | // array of [filename, title, anchor, descr, score]
470 | var results = [];
471 | $('#search-progress').empty();
472 |
473 | // lookup as object
474 | for (i = 0; i < objectterms.length; i++) {
475 | var others = [].concat(objectterms.slice(0, i),
476 | objectterms.slice(i+1, objectterms.length));
477 | results = results.concat(this.performObjectSearch(objectterms[i], others));
478 | }
479 |
480 | // lookup as search terms in fulltext
481 | results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
482 |
483 | // let the scorer override scores with a custom scoring function
484 | if (Scorer.score) {
485 | for (i = 0; i < results.length; i++)
486 | results[i][4] = Scorer.score(results[i]);
487 | }
488 |
489 | // now sort the results by score (in opposite order of appearance, since the
490 | // display function below uses pop() to retrieve items) and then
491 | // alphabetically
492 | results.sort(function(a, b) {
493 | var left = a[4];
494 | var right = b[4];
495 | if (left > right) {
496 | return 1;
497 | } else if (left < right) {
498 | return -1;
499 | } else {
500 | // same score: sort alphabetically
501 | left = a[1].toLowerCase();
502 | right = b[1].toLowerCase();
503 | return (left > right) ? -1 : ((left < right) ? 1 : 0);
504 | }
505 | });
506 |
507 | // for debugging
508 | //Search.lastresults = results.slice(); // a copy
509 | //console.info('search results:', Search.lastresults);
510 |
511 | // print the results
512 | var resultCount = results.length;
513 | function displayNextItem() {
514 | // results left, load the summary and display it
515 | if (results.length) {
516 | var item = results.pop();
517 | var listItem = $(' ');
518 | if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
519 | // dirhtml builder
520 | var dirname = item[0] + '/';
521 | if (dirname.match(/\/index\/$/)) {
522 | dirname = dirname.substring(0, dirname.length-6);
523 | } else if (dirname == 'index/') {
524 | dirname = '';
525 | }
526 | listItem.append($(' ').attr('href',
527 | DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
528 | highlightstring + item[2]).html(item[1]));
529 | } else {
530 | // normal html builders
531 | listItem.append($(' ').attr('href',
532 | item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
533 | highlightstring + item[2]).html(item[1]));
534 | }
535 | if (item[3]) {
536 | listItem.append($(' (' + item[3] + ') '));
537 | Search.output.append(listItem);
538 | listItem.slideDown(5, function() {
539 | displayNextItem();
540 | });
541 | } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
542 | var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;
543 | $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix),
544 | dataType: "text",
545 | complete: function(jqxhr, textstatus) {
546 | var data = jqxhr.responseText;
547 | if (data !== '' && data !== undefined) {
548 | listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
549 | }
550 | Search.output.append(listItem);
551 | listItem.slideDown(5, function() {
552 | displayNextItem();
553 | });
554 | }});
555 | } else {
556 | // no source available, just display title
557 | Search.output.append(listItem);
558 | listItem.slideDown(5, function() {
559 | displayNextItem();
560 | });
561 | }
562 | }
563 | // search finished, update title and status message
564 | else {
565 | Search.stopPulse();
566 | Search.title.text(_('Search Results'));
567 | if (!resultCount)
568 | Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
569 | else
570 | Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
571 | Search.status.fadeIn(500);
572 | }
573 | }
574 | displayNextItem();
575 | },
576 |
577 | /**
578 | * search for object names
579 | */
580 | performObjectSearch : function(object, otherterms) {
581 | var filenames = this._index.filenames;
582 | var docnames = this._index.docnames;
583 | var objects = this._index.objects;
584 | var objnames = this._index.objnames;
585 | var titles = this._index.titles;
586 |
587 | var i;
588 | var results = [];
589 |
590 | for (var prefix in objects) {
591 | for (var name in objects[prefix]) {
592 | var fullname = (prefix ? prefix + '.' : '') + name;
593 | if (fullname.toLowerCase().indexOf(object) > -1) {
594 | var score = 0;
595 | var parts = fullname.split('.');
596 | // check for different match types: exact matches of full name or
597 | // "last name" (i.e. last dotted part)
598 | if (fullname == object || parts[parts.length - 1] == object) {
599 | score += Scorer.objNameMatch;
600 | // matches in last name
601 | } else if (parts[parts.length - 1].indexOf(object) > -1) {
602 | score += Scorer.objPartialMatch;
603 | }
604 | var match = objects[prefix][name];
605 | var objname = objnames[match[1]][2];
606 | var title = titles[match[0]];
607 | // If more than one term searched for, we require other words to be
608 | // found in the name/title/description
609 | if (otherterms.length > 0) {
610 | var haystack = (prefix + ' ' + name + ' ' +
611 | objname + ' ' + title).toLowerCase();
612 | var allfound = true;
613 | for (i = 0; i < otherterms.length; i++) {
614 | if (haystack.indexOf(otherterms[i]) == -1) {
615 | allfound = false;
616 | break;
617 | }
618 | }
619 | if (!allfound) {
620 | continue;
621 | }
622 | }
623 | var descr = objname + _(', in ') + title;
624 |
625 | var anchor = match[3];
626 | if (anchor === '')
627 | anchor = fullname;
628 | else if (anchor == '-')
629 | anchor = objnames[match[1]][1] + '-' + fullname;
630 | // add custom score for some objects according to scorer
631 | if (Scorer.objPrio.hasOwnProperty(match[2])) {
632 | score += Scorer.objPrio[match[2]];
633 | } else {
634 | score += Scorer.objPrioDefault;
635 | }
636 | results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
637 | }
638 | }
639 | }
640 |
641 | return results;
642 | },
643 |
644 | /**
645 | * search for full-text terms in the index
646 | */
647 | performTermsSearch : function(searchterms, excluded, terms, titleterms) {
648 | var docnames = this._index.docnames;
649 | var filenames = this._index.filenames;
650 | var titles = this._index.titles;
651 |
652 | var i, j, file;
653 | var fileMap = {};
654 | var scoreMap = {};
655 | var results = [];
656 |
657 | // perform the search on the required terms
658 | for (i = 0; i < searchterms.length; i++) {
659 | var word = searchterms[i];
660 | var files = [];
661 | var _o = [
662 | {files: terms[word], score: Scorer.term},
663 | {files: titleterms[word], score: Scorer.title}
664 | ];
665 |
666 | // no match but word was a required one
667 | if ($u.every(_o, function(o){return o.files === undefined;})) {
668 | break;
669 | }
670 | // found search word in contents
671 | $u.each(_o, function(o) {
672 | var _files = o.files;
673 | if (_files === undefined)
674 | return
675 |
676 | if (_files.length === undefined)
677 | _files = [_files];
678 | files = files.concat(_files);
679 |
680 | // set score for the word in each file to Scorer.term
681 | for (j = 0; j < _files.length; j++) {
682 | file = _files[j];
683 | if (!(file in scoreMap))
684 | scoreMap[file] = {}
685 | scoreMap[file][word] = o.score;
686 | }
687 | });
688 |
689 | // create the mapping
690 | for (j = 0; j < files.length; j++) {
691 | file = files[j];
692 | if (file in fileMap)
693 | fileMap[file].push(word);
694 | else
695 | fileMap[file] = [word];
696 | }
697 | }
698 |
699 | // now check if the files don't contain excluded terms
700 | for (file in fileMap) {
701 | var valid = true;
702 |
703 | // check if all requirements are matched
704 | if (fileMap[file].length != searchterms.length)
705 | continue;
706 |
707 | // ensure that none of the excluded terms is in the search result
708 | for (i = 0; i < excluded.length; i++) {
709 | if (terms[excluded[i]] == file ||
710 | titleterms[excluded[i]] == file ||
711 | $u.contains(terms[excluded[i]] || [], file) ||
712 | $u.contains(titleterms[excluded[i]] || [], file)) {
713 | valid = false;
714 | break;
715 | }
716 | }
717 |
718 | // if we have still a valid result we can add it to the result list
719 | if (valid) {
720 | // select one (max) score for the file.
721 | // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
722 | var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
723 | results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
724 | }
725 | }
726 | return results;
727 | },
728 |
729 | /**
730 | * helper function to return a node containing the
731 | * search summary for a given text. keywords is a list
732 | * of stemmed words, hlwords is the list of normal, unstemmed
733 | * words. the first one is used to find the occurrence, the
734 | * latter for highlighting it.
735 | */
736 | makeSearchSummary : function(text, keywords, hlwords) {
737 | var textLower = text.toLowerCase();
738 | var start = 0;
739 | $.each(keywords, function() {
740 | var i = textLower.indexOf(this.toLowerCase());
741 | if (i > -1)
742 | start = i;
743 | });
744 | start = Math.max(start - 120, 0);
745 | var excerpt = ((start > 0) ? '...' : '') +
746 | $.trim(text.substr(start, 240)) +
747 | ((start + 240 - text.length) ? '...' : '');
748 | var rv = $('
').text(excerpt);
749 | $.each(hlwords, function() {
750 | rv = rv.highlightText(this, 'highlighted');
751 | });
752 | return rv;
753 | }
754 | };
755 |
756 | $(document).ready(function() {
757 | Search.init();
758 | });
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.3.1
2 | // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
9 | c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
10 | h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
11 | b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==
12 | null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
13 | function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
14 | e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
15 | function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
17 | c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};
24 | b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
25 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
26 | b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
27 | b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e /g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
28 | function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
29 | u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
30 | function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
31 | true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
32 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/up-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/up-pressed.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/_static/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/_static/up.png
--------------------------------------------------------------------------------
/docs/lunaticlog/html/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Contact — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | lunaticlog
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | Docs »
141 |
142 | Contact
143 |
144 |
145 |
146 |
147 |
148 | View page source
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
238 |
239 |
240 |
241 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/genindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Index — lunaticlog 0.1.0 documentation
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | lunaticlog
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | Docs »
140 |
141 | Index
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
Index
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
225 |
226 |
227 |
228 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | lunaticlog: Fake log generator — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | lunaticlog
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | Docs »
140 |
141 | lunaticlog: Fake log generator
142 |
143 |
144 |
145 |
146 |
147 | View page source
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
lunaticlog: Fake log generator
162 |
Lunaticlog is a mock HTTP log generator package, use it’s fake log workloads to test if your monitor / analyzer can survive various extreme conditions.
163 |
A simple usage example:
164 |
#content of test_sample.py
165 |
166 | from lunaticlog import apache_gen
167 |
168 | log_gen = apache_gen ( out_path = './apache.log' , mode = 'uniform' , rotation = True )
169 |
170 | log_gen . run ()
171 |
172 |
173 |
127.0.0.1 user-identifier frank [1/Oct/2017:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
174 | 127.0.0.1 user-identifier james [1/Oct/2017:13:55:37 -0700] "POST /README.txt HTTP/1.0" 200 2326
175 | 127.0.0.1 user-identifier putin [1/Oct/2017:13:55:38 -0700] "GET /image/cat.gif HTTP/1.0" 200 2326
176 |
177 |
178 |
182 |
183 |
Features
184 |
185 | Generate log in Apache Access format, Nginx format [TODO], AWS S3 format [TODO]
186 | Log file rotation configurable
187 | Can control the distributions of log fields contents
188 | Different log generation mode for stress testing
189 | Python3.4, Python3.5, Python3.6
190 |
191 |
192 |
196 |
197 |
License
198 |
MIT License
199 |
Copyright (c) 2017 WenyiXu
200 |
201 |
202 |
Contents
203 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
291 |
292 |
293 |
294 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/installation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Installation — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | lunaticlog
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | Docs »
144 |
145 | Installation
146 |
147 |
148 |
149 |
150 |
151 | View page source
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
Installation
166 |
167 |
Install from Source Code
168 |
Lunaticlog is actively developed on GitHub.
169 |
Clone the public repository:
170 |
$ git clone https://github.com/xuwenyihust/lunaticlog.git
171 |
172 |
173 |
Once you have a copy of the source code, install the lunatilog:
174 |
$ cd lunaticlog
175 |
176 | $ python setup.py build
177 |
178 | $ python setup.py install
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
253 |
254 |
255 |
256 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/license.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | License — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | lunaticlog
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | Docs »
140 |
141 | License
142 |
143 |
144 |
145 |
146 |
147 | View page source
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
License
162 |
Distributed under the terms of the MIT license
163 |
MIT License
164 |
165 | Copyright ( c ) 2017 WenyiXu
166 |
167 | Permission is hereby granted , free of charge , to any person obtaining a copy
168 | of this software and associated documentation files ( the "Software" ), to deal
169 | in the Software without restriction , including without limitation the rights
170 | to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
171 | copies of the Software , and to permit persons to whom the Software is
172 | furnished to do so , subject to the following conditions :
173 |
174 | The above copyright notice and this permission notice shall be included in all
175 | copies or substantial portions of the Software .
176 |
177 | THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
178 | IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
179 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
180 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
181 | LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
182 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
254 |
255 |
256 |
257 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/docs/lunaticlog/html/objects.inv
--------------------------------------------------------------------------------
/docs/lunaticlog/html/quickstart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | QuickStart — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | lunaticlog
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | Docs »
148 |
149 | QuickStart
150 |
151 |
152 |
153 |
154 |
155 | View page source
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
QuickStart
170 |
Sometimes we want to quickly test our log monitor and analyzer, to see if they can perform correctly,but don’t have log sources in hand. Lunaticlog gives you the ability to create fake log loads, which supports log rotation and content distribution control. It can also stress testing the system by generating traffic spikes.
171 |
172 |
Log Generating Summary
173 |
Begin by importing a log generator module:
174 |
>>> from lunaticlog import apache_gen
175 |
176 |
177 |
Instantiate the generator and set the output path:
178 |
>>> log_gen = apache_gen ( out_path = './apache.log' )
179 |
180 |
181 |
Finally let it begin to generate logs:
182 |
185 |
Now, we can check the output path that we set to see the generated logs.
186 |
187 |
208 |
209 |
Log Roatation
210 |
Set attribute rotation_size
to rotate logs when current log file achieves the max size:
211 |
# content of file config/apache_gen.json
212 | "rotation_size": 10000
213 |
214 |
215 |
And turn on the log rotation when creating generator objects:
216 |
log_gen = apache_gen(out_path='./apache.log', rotation=True)
217 |
218 |
219 |
220 |
221 |
Log Field Content Distribution
222 |
Since we are trying to build a fake log generator to simulate a real cluster, we are eager to add as much randomness as possible to the generated logs, to make it look more similar to real ones.
223 |
To make them more realistic, we also want to fill in log fileds using contents with some given distributions.
224 |
For example, we may want to generate more GET
messages than POST
ones.
225 |
To configure the distributions, use Apache Access Log’s HTTP method field as an example:
226 |
# content of config/apache_gen.json
227 | "methods": ["GET", "POST", "PUT", "DELETE"],
228 | "methods_p": [0.7,0.1,0.1,0.1],
229 |
230 |
231 |
methods_p
list configures the distributions of corresponding HTTP methods in list methods
.
232 |
233 |
234 |
Log Generation Mode
235 |
Lunaticlogs can create chaos to help you stress test your system. Now it has 3 different log generation modes:
236 |
237 | Uniform Mode
238 |
239 | Generate logs at a random rate, which is uniformly distributed.
240 |
241 |
242 |
243 |
244 |
245 | Push Mode
246 |
247 | Generate logs at highest speed configured.
248 |
249 |
250 |
251 |
252 |
253 | Spike Mode
254 |
255 | Generate logs at sudden very high rates periodically.
256 |
257 |
258 |
259 |
260 |
Select the modes during generator instantiation:
261 |
log_gen = apache_gen ( out_path = './apache.log' , mode = 'uniform' )
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
336 |
337 |
338 |
339 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Search — lunaticlog 0.1.0 documentation
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | lunaticlog
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | Docs »
139 |
140 | Search
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | Please activate JavaScript to enable the search
159 | functionality.
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
229 |
230 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
--------------------------------------------------------------------------------
/docs/lunaticlog/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({docnames:["contact","index","installation","license","quickstart"],envversion:52,filenames:["contact.rst","index.rst","installation.rst","license.rst","quickstart.rst"],objects:{},objnames:{},objtypes:{},terms:{"10_6_4":4,"3e57427f3exampl":4,"79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2b":4,"final":4,"import":[1,4],"new":4,"public":2,"true":[1,4],"try":4,AND:3,AWS:1,And:4,BUT:3,FOR:3,For:[1,4],NOT:3,THE:3,The:3,USE:3,WITH:3,abil:4,abov:3,access:[1,4],achiev:4,action:3,activ:2,add:4,admin:4,ajax:4,all:3,also:4,amazon:4,analyz:[1,4],ani:3,apach:[1,4],apache_gen:[1,4],apache_pb:[1,4],applewebkit:4,aris:3,associ:3,attribut:4,aug:4,author:3,begin:4,build:[2,4],can:[1,4],cat:1,chao:4,charg:3,check:4,chrome:4,claim:3,clone:2,cluster:4,com:[0,2,4],condit:[1,3],config:4,configur:[1,4],connect:3,contact:1,contract:3,control:[1,4],copi:[2,3],copyright:[1,3],correctli:4,correspond:4,creat:4,current:4,damag:3,deal:3,delet:4,develop:2,differ:[1,4],distribut:[1,3],document:3,don:4,dure:4,eager:4,email:0,event:3,exampl:[1,4],express:3,extrem:1,fake:4,feb:4,field:1,file:[1,3,4],fill:4,fit:3,follow:3,format:1,frank:[1,4],free:3,from:[1,3,4],full:1,furnish:3,gecko:4,get:[1,4],gif:[1,4],git:2,github:[0,1,2],give:4,given:4,gmail:0,grant:3,hand:4,has:4,have:[2,4],help:4,herebi:3,high:4,highest:4,holder:3,html:1,http:[0,1,2,4],identifi:[1,4],imag:1,impli:3,includ:[1,3],instal:1,instanti:4,intel:4,jame:1,json:4,khtml:4,kind:3,let:4,liabil:3,liabl:3,like:4,limit:3,list:4,load:4,log_gen:[1,4],look:4,lunaticlog:[2,4],lunatilog:2,mac:4,macintosh:4,mai:4,make:4,max:4,merchant:3,merg:3,messag:4,method:4,methods_p:4,mit:[1,3],mock:1,mode:1,modifi:3,modul:4,monitor:[1,4],more:4,mozilla:4,much:4,mybucket:4,nginx:[1,4],noninfring:3,notic:3,now:4,object:4,obtain:3,oct:[1,4],onc:2,ones:4,other:3,otherwis:3,our:4,out:3,out_path:[1,4],output:4,packag:1,particular:3,path:4,pdf:1,perform:4,period:4,permiss:3,permit:3,person:3,php:4,pleas:1,portion:3,possibl:4,post:[1,4],provid:3,publish:3,purpos:3,push:4,put:4,putin:1,python3:1,python:2,quickli:4,quickstart:1,random:4,rate:4,readm:1,real:4,realist:4,repositori:2,rest:4,restrict:3,right:3,roatat:1,rotat:[1,4],rotation_s:4,run:[1,4],s3consol:4,safari:4,see:[1,4],select:4,sell:3,set:4,setup:2,shall:3,similar:4,simpl:1,simul:4,sinc:4,size:4,softwar:3,some:4,sometim:4,sourc:4,speed:4,spike:4,stress:[1,4],subject:3,sublicens:3,substanti:3,sudden:4,summari:1,support:1,surviv:1,system:4,term:3,test:[1,4],test_sampl:1,than:4,thei:4,them:4,thi:3,todo:[1,4],tort:3,traffic:4,turn:4,tutori:1,txt:1,under:3,uniform:[1,4],uniformli:4,usag:1,use:[1,3,4],user:[1,4],using:4,variou:1,veri:4,version:4,want:4,warranti:3,wenyixu101:0,wenyixu:[1,3],when:4,whether:3,which:4,whom:3,without:3,wordpress3:4,workload:1,www:4,xuwenyihust:[0,1,2],you:[2,4],your:[1,4]},titles:["Contact","lunaticlog: Fake log generator","Installation","License","QuickStart"],titleterms:{code:[1,2],contact:0,content:[1,4],distribut:4,document:1,fake:1,featur:1,field:4,format:4,from:2,gener:[1,4],instal:2,licens:[1,3],log:[1,4],lunaticlog:1,mode:4,quickstart:4,roatat:4,sourc:[1,2],summari:4,support:4}})
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # lunaticlog documentation build configuration file, created by
5 | # sphinx-quickstart on Mon May 8 15:31:55 2017.
6 | #
7 | # This file is execfile()d with the current directory set to its
8 | # containing dir.
9 | #
10 | # Note that not all possible configuration values are present in this
11 | # autogenerated file.
12 | #
13 | # All configuration values have a default; values that are commented out
14 | # serve to show the default.
15 |
16 | # If extensions (or modules to document with autodoc) are in another directory,
17 | # add these directories to sys.path here. If the directory is relative to the
18 | # documentation root, use os.path.abspath to make it absolute, like shown here.
19 | #
20 | # import os
21 | # import sys
22 | # sys.path.insert(0, os.path.abspath('.'))
23 | import sphinx_rtd_theme
24 |
25 | # -- General configuration ------------------------------------------------
26 |
27 | # If your documentation needs a minimal Sphinx version, state it here.
28 | #
29 | # needs_sphinx = '1.0'
30 |
31 | # Add any Sphinx extension module names here, as strings. They can be
32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 | # ones.
34 | extensions = ['sphinx.ext.autodoc',
35 | 'sphinx.ext.intersphinx',
36 | 'sphinx.ext.ifconfig',
37 | 'sphinx.ext.githubpages']
38 |
39 | # Add any paths that contain templates here, relative to this directory.
40 | templates_path = ['_templates']
41 |
42 | # The suffix(es) of source filenames.
43 | # You can specify multiple suffix as a list of string:
44 | #
45 | # source_suffix = ['.rst', '.md']
46 | source_suffix = '.rst'
47 |
48 | # The master toctree document.
49 | master_doc = 'index'
50 |
51 | # General information about the project.
52 | project = 'lunaticlog'
53 | copyright = '2017, Wenyi Xu'
54 | author = 'Wenyi Xu'
55 |
56 | # The version info for the project you're documenting, acts as replacement for
57 | # |version| and |release|, also used in various other places throughout the
58 | # built documents.
59 | #
60 | # The short X.Y version.
61 | version = '0.1.0'
62 | # The full version, including alpha/beta/rc tags.
63 | release = '0.1.0'
64 |
65 | # The language for content autogenerated by Sphinx. Refer to documentation
66 | # for a list of supported languages.
67 | #
68 | # This is also used if you do content translation via gettext catalogs.
69 | # Usually you set "language" from the command line for these cases.
70 | language = None
71 |
72 | # List of patterns, relative to source directory, that match files and
73 | # directories to ignore when looking for source files.
74 | # This patterns also effect to html_static_path and html_extra_path
75 | exclude_patterns = []
76 |
77 | # The name of the Pygments (syntax highlighting) style to use.
78 | pygments_style = 'sphinx'
79 |
80 | # If true, `todo` and `todoList` produce output, else they produce nothing.
81 | todo_include_todos = False
82 |
83 |
84 | # -- Options for HTML output ----------------------------------------------
85 |
86 | # The theme to use for HTML and HTML Help pages. See the documentation for
87 | # a list of builtin themes.
88 | #
89 | #html_theme = 'alabaster'
90 | html_theme = "sphinx_rtd_theme"
91 | #html_theme = 'classic'
92 |
93 | # Theme options are theme-specific and customize the look and feel of a theme
94 | # further. For a list of options available for each theme, see the
95 | # documentation.
96 | #
97 | # html_theme_options = {}
98 |
99 | # Add any paths that contain custom static files (such as style sheets) here,
100 | # relative to this directory. They are copied after the builtin static files,
101 | # so a file named "default.css" will overwrite the builtin "default.css".
102 | #html_static_path = ['_static']
103 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
104 |
105 | # -- Options for HTMLHelp output ------------------------------------------
106 |
107 | # Output file base name for HTML help builder.
108 | htmlhelp_basename = 'lunaticlogdoc'
109 |
110 |
111 | # -- Options for LaTeX output ---------------------------------------------
112 |
113 | latex_elements = {
114 | # The paper size ('letterpaper' or 'a4paper').
115 | #
116 | # 'papersize': 'letterpaper',
117 |
118 | # The font size ('10pt', '11pt' or '12pt').
119 | #
120 | # 'pointsize': '10pt',
121 |
122 | # Additional stuff for the LaTeX preamble.
123 | #
124 | # 'preamble': '',
125 |
126 | # Latex figure (float) alignment
127 | #
128 | # 'figure_align': 'htbp',
129 | }
130 |
131 | # Grouping the document tree into LaTeX files. List of tuples
132 | # (source start file, target name, title,
133 | # author, documentclass [howto, manual, or own class]).
134 | latex_documents = [
135 | (master_doc, 'lunaticlog.tex', 'lunaticlog Documentation',
136 | 'Wenyi Xu', 'manual'),
137 | ]
138 |
139 |
140 | # -- Options for manual page output ---------------------------------------
141 |
142 | # One entry per manual page. List of tuples
143 | # (source start file, name, description, authors, manual section).
144 | man_pages = [
145 | (master_doc, 'lunaticlog', 'lunaticlog Documentation',
146 | [author], 1)
147 | ]
148 |
149 |
150 | # -- Options for Texinfo output -------------------------------------------
151 |
152 | # Grouping the document tree into Texinfo files. List of tuples
153 | # (source start file, target name, title, author,
154 | # dir menu entry, description, category)
155 | texinfo_documents = [
156 | (master_doc, 'lunaticlog', 'lunaticlog Documentation',
157 | author, 'lunaticlog', 'One line description of project.',
158 | 'Miscellaneous'),
159 | ]
160 |
161 |
162 |
163 |
164 | # Example configuration for intersphinx: refer to the Python standard library.
165 | intersphinx_mapping = {'https://docs.python.org/': None}
166 |
--------------------------------------------------------------------------------
/docs/source/contact.rst:
--------------------------------------------------------------------------------
1 | .. _contact:
2 |
3 | Contact
4 | -------
5 |
6 | - Email: wenyixu101@gmail.com
7 |
8 | - Github: https://github.com/xuwenyihust
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. _toc:
2 |
3 | lunaticlog: Fake log generator
4 | ==============================
5 |
6 | Lunaticlog is a mock HTTP log generator package, use it's fake log workloads to test if your monitor / analyzer can survive various extreme conditions.
7 |
8 | A simple usage example:
9 |
10 | .. code-block:: python
11 |
12 | #content of test_sample.py
13 |
14 | from lunaticlog import apache_gen
15 |
16 | log_gen = apache_gen(out_path='./apache.log', mode='uniform', rotation=True)
17 |
18 | log_gen.run()
19 |
20 | .. code-block:: none
21 |
22 | 127.0.0.1 user-identifier frank [1/Oct/2017:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
23 | 127.0.0.1 user-identifier james [1/Oct/2017:13:55:37 -0700] "POST /README.txt HTTP/1.0" 200 2326
24 | 127.0.0.1 user-identifier putin [1/Oct/2017:13:55:38 -0700] "GET /image/cat.gif HTTP/1.0" 200 2326
25 |
26 |
27 | Source Code
28 | -----------
29 |
30 | Get the `source code
31 | `_.
32 |
33 | Features
34 | --------
35 |
36 | - Generate log in Apache Access format, Nginx format [TODO], AWS S3 format [TODO]
37 |
38 | - Log file rotation configurable
39 |
40 | - Can control the distributions of log fields contents
41 |
42 | - Different log generation mode for stress testing
43 |
44 | - Python3.4, Python3.5, Python3.6
45 |
46 | Documentation
47 | -------------
48 |
49 | For full documentation, including installation, tutorials and PDF documents, please see https://xuwenyihust.github.io/lunaticlog/lunaticlog/html/.
50 |
51 | License
52 | -------
53 | `MIT
54 | `_ License
55 |
56 | Copyright (c) 2017 WenyiXu
57 |
58 |
59 | Contents
60 | --------
61 | .. toctree::
62 | :maxdepth: 2
63 |
64 | installation
65 |
66 | quickstart
67 |
68 | contact
69 |
70 | license
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/docs/source/installation.rst:
--------------------------------------------------------------------------------
1 | .. _installation:
2 |
3 | Installation
4 | ============
5 |
6 |
7 | Install from Source Code
8 | ------------------------
9 |
10 | Lunaticlog is actively developed on GitHub.
11 |
12 | Clone the public repository:
13 |
14 | .. code-block:: none
15 |
16 | $ git clone https://github.com/xuwenyihust/lunaticlog.git
17 |
18 |
19 | Once you have a copy of the source code, install the lunatilog:
20 |
21 | .. code-block:: none
22 |
23 | $ cd lunaticlog
24 |
25 | $ python setup.py build
26 |
27 | $ python setup.py install
28 |
29 |
--------------------------------------------------------------------------------
/docs/source/license.rst:
--------------------------------------------------------------------------------
1 | .. _license:
2 |
3 | License
4 | -------
5 |
6 | Distributed under the terms of the `MIT`_ license
7 |
8 | ::
9 |
10 | MIT License
11 |
12 | Copyright (c) 2017 WenyiXu
13 |
14 | Permission is hereby granted, free of charge, to any person obtaining a copy
15 | of this software and associated documentation files (the "Software"), to deal
16 | in the Software without restriction, including without limitation the rights
17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | copies of the Software, and to permit persons to whom the Software is
19 | furnished to do so, subject to the following conditions:
20 |
21 | The above copyright notice and this permission notice shall be included in all
22 | copies or substantial portions of the Software.
23 |
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | .. _`MIT`: https://github.com/xuwenyihust/lunaticlog/blob/master/LICENSE
32 |
--------------------------------------------------------------------------------
/docs/source/quickstart.rst:
--------------------------------------------------------------------------------
1 | .. _quickstart:
2 |
3 | QuickStart
4 | ==========
5 |
6 | Sometimes we want to quickly test our log monitor and analyzer, to see if they can perform correctly,but don't have log sources in hand. Lunaticlog gives you the ability to create fake log loads, which supports log rotation and content distribution control. It can also stress testing the system by generating traffic spikes.
7 |
8 | Log Generating Summary
9 | ----------------------
10 |
11 | Begin by importing a log generator module:
12 |
13 | .. code-block:: python
14 |
15 | >>> from lunaticlog import apache_gen
16 |
17 | Instantiate the generator and set the output path:
18 |
19 | .. code-block:: python
20 |
21 | >>> log_gen = apache_gen(out_path='./apache.log')
22 |
23 | Finally let it begin to generate logs:
24 |
25 | .. code-block:: python
26 |
27 | >>> log_gen.run()
28 |
29 | Now, we can check the output path that we set to see the generated logs.
30 |
31 |
32 | Log Format Support
33 | ------------------
34 |
35 | - Apache Access Log
36 |
37 | .. code-block:: none
38 |
39 | 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
40 |
41 | - [TODO] Nginx Access Log
42 |
43 | .. code-block:: none
44 |
45 | 123.65.150.10 - - [23/Aug/2010:03:50:59 +0000] "POST /wordpress3/wp-admin/admin-ajax.php HTTP/1.1" 200 2 "http://www.example.com/wordpress3/wp-admin/post-new.php" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.25 Safari/534.3"
46 |
47 | - [TODO] Amazon S3 Log
48 |
49 | .. code-block:: none
50 |
51 | 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be mybucket [06/Feb/2014:00:00:38 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be 3E57427F3EXAMPLE REST.GET.VERSIONING - "GET /mybucket?versioning HTTP/1.1" 200 - 113 - 7 - "-" "S3Console/0.4" -
52 |
53 |
54 | Log Roatation
55 | -------------
56 |
57 | Set attribute ``rotation_size`` to rotate logs when current log file achieves the max size:
58 |
59 | .. code-block:: none
60 |
61 | # content of file config/apache_gen.json
62 | "rotation_size": 10000
63 |
64 | And turn on the log rotation when creating generator objects:
65 |
66 | .. code-block:: none
67 |
68 | log_gen = apache_gen(out_path='./apache.log', rotation=True)
69 |
70 |
71 | Log Field Content Distribution
72 | ------------------------------
73 |
74 | Since we are trying to build a fake log generator to simulate a real cluster, we are eager to add as much randomness as possible to the generated logs, to make it look more similar to real ones.
75 |
76 | To make them more realistic, we also want to fill in log fileds using contents with some given distributions.
77 |
78 | For example, we may want to generate more ``GET`` messages than ``POST`` ones.
79 |
80 | To configure the distributions, use Apache Access Log's HTTP method field as an example:
81 |
82 | .. code-block:: none
83 |
84 | # content of config/apache_gen.json
85 | "methods": ["GET", "POST", "PUT", "DELETE"],
86 | "methods_p": [0.7,0.1,0.1,0.1],
87 |
88 | ``methods_p`` list configures the distributions of corresponding HTTP methods in list ``methods``.
89 |
90 |
91 | Log Generation Mode
92 | -------------------
93 |
94 | Lunaticlogs can create chaos to help you stress test your system. Now it has 3 different log generation modes:
95 |
96 |
97 | - Uniform Mode
98 |
99 | Generate logs at a random rate, which is uniformly distributed.
100 |
101 | .. image:: https://raw.githubusercontent.com/xuwenyihust/lunaticlog/master/img/mode_uniform.png
102 | :width: 320 px
103 | :height: 240 px
104 | :align: center
105 |
106 | - Push Mode
107 |
108 | Generate logs at highest speed configured.
109 |
110 | .. image:: https://raw.githubusercontent.com/xuwenyihust/lunaticlog/master/img/mode_push.png
111 | :width: 320 px
112 | :height: 240 px
113 | :align: center
114 |
115 | - Spike Mode
116 |
117 | Generate logs at sudden very high rates periodically.
118 |
119 | .. image:: https://raw.githubusercontent.com/xuwenyihust/lunaticlog/master/img/mode_spike.png
120 | :width: 320 px
121 | :height: 240 px
122 | :align: center
123 |
124 |
125 | Select the modes during generator instantiation:
126 |
127 | .. code-block:: python
128 |
129 | log_gen = apache_gen(out_path='./apache.log', mode='uniform')
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/img/mode_push.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/img/mode_push.png
--------------------------------------------------------------------------------
/img/mode_spike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/img/mode_spike.png
--------------------------------------------------------------------------------
/img/mode_uniform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuwenyihust/lunaticlog/d0be34065c716f166cfba992cfcbb9afeffc2167/img/mode_uniform.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy==1.8.2
2 | pytest==3.0.5
3 |
--------------------------------------------------------------------------------
/scripts/bandwidth.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | def main():
6 | f = open("../apache_push.log", 'r')
7 | lines = f.readlines()
8 |
9 | #for i in range(3):
10 | # print(lines[i])
11 |
12 | time_li = []
13 |
14 | for line in lines:
15 | time_and_after = line.split('[')[1]
16 | time_and_0700 = time_and_after.split(']')[0]
17 | time = time_and_0700.split()[0]
18 | time_li.append(time)
19 |
20 | #print(time_li[:5])
21 |
22 | datetime_li = [datetime.strptime(x, "%d/%b/%Y:%H:%M:%S") for x in time_li]
23 | #print(datetime_li[0])
24 |
25 | base = datetime_li[0]
26 | offset_li = [(x - base) for x in datetime_li]
27 | #print(offset_li[0].total_seconds())
28 |
29 | offset_sec_li = [x.total_seconds() for x in offset_li]
30 | #print(offset_sec_li[:10])
31 |
32 |
33 | plt.hist(offset_sec_li, bins=150, alpha=0.75)
34 | plt.xlabel('Time')
35 | plt.ylabel('Bandwidth')
36 | plt.title('Log traffic under push mode')
37 | plt.show()
38 |
39 |
40 |
41 | if __name__ == '__main__':
42 | main()
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | # This flag says that the code is written to work on both Python 2 and Python
3 | # 3. If at all possible, it is good practice to do this. If you cannot, you
4 | # will need to generate wheels for each Python version that you support.
5 | #universal=1
6 |
7 | [aliases]
8 | test=pytest
9 |
10 | [tool:pytest]
11 | python_files = tests/*_test.py
12 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | # Parse the requirements.txt to get the dependencies
4 | #with open('requirements.txt') as f:
5 | # required = f.read().splitlines()
6 |
7 | setup(
8 | name = 'lunaticlog',
9 | version = '0.1.2',
10 | description = 'A fake log generator to test your monitor system.',
11 | url = 'https://github.com/xuwenyihust/lunaticlog',
12 | author = 'Wenyi Xu',
13 | author_email = 'wenyixu101@gmail.com',
14 | license = 'MIT',
15 | keywords='fake log monitor apache',
16 |
17 | packages = find_packages(),
18 |
19 | # install_requires = required,
20 |
21 | package_data={
22 | 'configuration': ['conf/*.json'],
23 | },
24 |
25 | test_suite = 'tests',
26 | setup_requires=['pytest-runner'],
27 | tests_require = ['pytest']
28 | )
29 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
1 | from .base_generator import log_gen
2 | from .apache_generator import apache_gen
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/apache_generator.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | import json
4 | import logging
5 | import argparse
6 | import asyncio
7 | import datetime
8 | from asyncio import coroutine
9 | import numpy
10 | from subprocess import check_call
11 | from . import log_gen
12 |
13 | #################################
14 | ##
15 | ## Apache Access Log Generator
16 | ##
17 | #################################
18 | class apache_gen(log_gen):
19 |
20 | def __init__(self, out_path='./apache.log', out_format=['stdout', 'log'], mode='uniform', rotation=False, forever=True, count=1):
21 | # Load configuration data
22 | config_file = './config/apache_gen.json'
23 | with open(config_file, 'r') as f:
24 | self.config = json.load(f)
25 | # Assign the lines to generate
26 | self._lines_full = ['heartbeat', 'access']
27 | self._lines_gen = [self.heartbeat_lines(), self.access_lines()]
28 | self._lines = self.config["lines"]
29 | # Assign the http methods to generate
30 | self._methods = self.config["methods"]
31 | # Assign the methods distribution
32 | self._methods_p = self.config["methods_p"]
33 | # Run forever or not
34 | self._forever = forever
35 | # Total # of logs to generate
36 | self._count = count
37 | # Assign the intervals
38 | self._heartbeat_interval = self.config["heartbeat_interval"]
39 | self._access_interval = self.config["access_interval"]
40 | # Assign the generator mode
41 | self._mode = mode
42 | # Assign the rotation attribute
43 | self._rotation = rotation
44 | self._rotation_size = self.config["rotation_size"]
45 | self.rotation_id = 1
46 | # Assign the output format
47 | self._out_format = out_format
48 | # Assign the output path
49 | self._out_log = out_path
50 | if 'log' in self.out_format or 'gzip' in self.out_format:
51 | self.f_log = open(self.out_log, 'w')
52 | #self.out_gz
53 |
54 | ######################### property ###############################
55 |
56 | # Predefined lines_full
57 | # ['heartbeat', 'access']
58 | @property
59 | def lines_full(self):
60 | return self._lines_full
61 |
62 | # Predefined lines_gen
63 | # [self.heartbeat_lines(), self.access_lines()]
64 | @property
65 | def lines_gen(self):
66 | return self._lines_gen
67 |
68 | @property
69 | def lines(self):
70 | return self._lines
71 |
72 | @lines.setter
73 | def lines(self, val):
74 | if type(val) != type([1,2,3]):
75 | raise Exception('lines should be a list.')
76 | lines_set = set(val)
77 | lines_full_set = set(self.lines_full)
78 | if not lines_set.issubset(lines_full_set):
79 | raise Exception("Unsupported line types.")
80 | if len(lines_set) != len(val):
81 | raise Exception("Duplicated line types.")
82 | self._lines = val
83 |
84 | @property
85 | def methods(self):
86 | return self._methods
87 |
88 | @methods.setter
89 | def methods(self, val):
90 | if type(val) != type([1,2,3]):
91 | raise Exception('methods should be a list.')
92 | methods_set = set(val)
93 | methods_full_set = set(['GET', 'POST', 'PUT', 'DELETE'])
94 | if not methods_set.issubset(methods_full_set):
95 | raise Exception("Unsupported method types.")
96 | if len(methods_set) != len(val):
97 | raise Exception("Duplicated method types.")
98 | self._methods = val
99 |
100 | @property
101 | def methods_p(self):
102 | return self._methods_p
103 |
104 | @methods_p.setter
105 | def methods_p(self, val):
106 | if type(val) != type([1,2,3]):
107 | raise Exception('methods_p should be a list.')
108 | if len(val) != len(self.methods):
109 | raise Exception("Length of methods_p doesn't equal length of methods.")
110 | if abs(1-sum(val)) > 0.01:
111 | raise Exception("Sum of methods_p must equals 1.")
112 | for x in val:
113 | if x < 0 or x > 1:
114 | raise Exception("All members of methods_p must be in the range of 0 to 1 ")
115 | self._methods_p = val
116 |
117 | @property
118 | def forever(self):
119 | return self._forever
120 |
121 | @forever.setter
122 | def forever(self, val):
123 | if val not in [True, False]:
124 | raise Exception("forever must be either True or False")
125 | self._forever = val
126 |
127 | @property
128 | def count(self):
129 | return self._count
130 |
131 | @count.setter
132 | def count(self, val):
133 | self._count = val
134 |
135 | @property
136 | def heartbeat_interval(self):
137 | return self._heartbeat_interval
138 |
139 |
140 | @property
141 | def rotation(self):
142 | return self._rotation
143 |
144 | @rotation.setter
145 | def rotation(self, val):
146 | if val not in [True, False]:
147 | raise Exception("rotation must be either True or False")
148 | self._rotation = val
149 |
150 | @property
151 | def rotation_size(self):
152 | return self._rotation_size
153 |
154 | @rotation_size.setter
155 | def rotation_size(self, val):
156 | # rotation_size must be an integer
157 | if type(val) != type(1):
158 | raise Exception("rotation_size must be an integer")
159 | self._rotation_size = val
160 |
161 | # When given heartbeat_interval,
162 | # heartbeat must be one of the methods to be generated
163 | @heartbeat_interval.setter
164 | def heartbeat_interval(self, val):
165 | if type(val) != type(1) and type(val) != type(0.5):
166 | raise Exception("heartbeat_interval value should be either integer or decimal")
167 | if val is not None and 'heartbeat' not in self.lines:
168 | raise Exception("Only set heartbeat_interval when generate heartbeat")
169 | self._heartbeat_interval = val
170 |
171 | @property
172 | def access_interval(self):
173 | return self._access_interval
174 |
175 | @access_interval.setter
176 | def access_interval(self, val):
177 | if type(val) != type([1,2,3]):
178 | raise Exception("access_interval should be a list")
179 | if len(val) != 2:
180 | raise Exception("access_interval should be a list containing 2 elements")
181 | if type(val[0]) != type(1) and type(val[0]) != type(0.5):
182 | raise Exception("access_interval[0] should be either integer or decimal")
183 | if type(val[1]) != type(1) and type(val[1]) != type(0.5):
184 | raise Exception("access_interval[1] should be either integer or decimal")
185 | if val[0] >= val[1]:
186 | raise Exception("access_interval[0] should be smaller than access_interval[1]")
187 | self._access_interval = val
188 |
189 | @property
190 | def mode(self):
191 | return self._mode
192 |
193 | @mode.setter
194 | def mode(self, val):
195 | if val not in ['uniform', 'push', 'spike']:
196 | raise Exception("Unrecognized mode")
197 |
198 | @property
199 | def out_format(self):
200 | return self._out_format
201 |
202 | @out_format.setter
203 | def out_format(self, val):
204 | if type(val) != type([1,2,3]):
205 | raise Exception("out_format should be a list")
206 | if len(val) == 0:
207 | raise Exception("Should select at least 1 output format")
208 | out_format_set = set(val)
209 | if not out_format_set.issubset(set(['stdout', 'log', 'gzip'])):
210 | raise Exception("Unsupported output format")
211 | self._out_format = val
212 |
213 | @property
214 | def out_log(self):
215 | return self._out_log
216 |
217 | @out_log.setter
218 | def out_log(self, val):
219 | try:
220 | f = open(val, 'w')
221 | except:
222 | raise Exception("Invalid output path")
223 | self._out_log = val
224 |
225 | ######################### run ###############################
226 |
227 | def run(self):
228 | loop = asyncio.new_event_loop()
229 | asyncio.set_event_loop(loop)
230 | try:
231 | loop.run_until_complete(
232 | asyncio.wait([self.lines_gen[self.lines_full.index(x)] for x in self.lines])
233 | )
234 | finally:
235 | loop.close()
236 | if 'log' in self.out_format or 'gzip' in self.out_format:
237 | self.f_log.close()
238 | if 'gzip' in self.out_format:
239 | check_call(['gzip', self.out_log])
240 |
241 | ######################### coroutine ###############################
242 |
243 | @coroutine
244 | def heartbeat_lines(self):
245 | while self.forever or self.count > 0:
246 | t = self.get_time_field()
247 | self.output_heartbeat(t)
248 | #self.log.info('- - - [%s] "%s" - -', t, 'HEARTBEAT')
249 | if self.count > 0:
250 | self.count -= 1
251 | yield from asyncio.sleep(self.heartbeat_interval)
252 |
253 | # Output the heartbeat line (to stdout, file, ...)
254 | def output_heartbeat(self, t):
255 | string = '- - - [' + t + '] "' + 'HEARTBEAT" - -'
256 | if 'stdout' in self.out_format:
257 | print(string)
258 | if 'log' in self.out_format:
259 | self.rotate()
260 | #self.f_log.write(self.out_log+str(self.f_log.tell())+'\n')
261 | self.f_log.write(string + '\n')
262 |
263 |
264 | # Rotate output
265 | def rotate(self):
266 | if self.f_log.tell() > self.rotation_size:
267 | self.f_log.close()
268 | if self.out_log.split('.')[-1] in ['log', 'txt']:
269 | self.out_log += '.1'
270 | else:
271 | self.out_log = '.'.join(self.out_log.split('.')[:-1])
272 | self.rotation_id += 1
273 | self.out_log += '.'
274 | self.out_log += str(self.rotation_id)
275 | self.f_log = open(self.out_log, 'w')
276 |
277 |
278 | # Derive the timestamp from current time
279 | def get_time_field(self):
280 | return datetime.datetime.now().strftime('%d/%b/%Y:%H:%M:%S -0700')
281 |
282 |
283 | @coroutine
284 | def access_lines(self):
285 | while self.forever or self.count > 0:
286 | # Generate different fields in the access log
287 | ip = self.get_ip()
288 | user_identifier = self.get_user_identifier()
289 | user_id = self.get_user_id()
290 | t = self.get_time_field()
291 | method = self.get_method()
292 | resource = self.get_resource()
293 | version = self.get_version()
294 | msg = self.get_msg(method, resource, version)
295 |
296 | code = self.get_code()
297 | size = self.get_size()
298 | # Output the generated access line
299 | self.output_access(ip, user_identifier, user_id, t, msg, code, size)
300 | # Decrease the counter
301 | if self.count > 0:
302 | self.count -= 1
303 |
304 |
305 | sleep_time = self.get_access_sleep_time()
306 | yield from asyncio.sleep(sleep_time)
307 |
308 |
309 |
310 | # Output the access line (to stdout, file, ...)
311 | def output_access(self, ip, user_identifier, user_id, t, msg, code, size):
312 | string = ip+' '+user_identifier+' '+user_id+' '+'['+t+'] "'+msg+'" '+code+' '+str(size)
313 | if 'stdout' in self.out_format:
314 | print(string)
315 | if 'log' in self.out_format:
316 | self.rotate()
317 | self.f_log.write(string + '\n')
318 |
319 |
320 | # Generate the ip field for the access line
321 | def get_ip(self):
322 | return '.'.join(str(random.randint(0, 255)) for i in range(4))
323 |
324 | # Generate the user_identifier field for the access line
325 | def get_user_identifier(self):
326 | return '-'
327 |
328 | # Generate the user_id field for the access line
329 | def get_user_id(self):
330 | user_id_li = self.config["user_id"]
331 | return user_id_li[random.randint(0, len(user_id_li)-1)]
332 |
333 | # Generate the HTTP method field for the access line
334 | def get_method(self):
335 | return numpy.random.choice(self.methods, p=self.methods_p)
336 |
337 | # Generate the resource field for the access line
338 | def get_resource(self):
339 | return self.config["resource"]
340 |
341 | # Generate the version field for the access line
342 | def get_version(self):
343 | return self.config["version"]
344 |
345 | # Generate the message field for the access line
346 | def get_msg(self, method, resource, version):
347 | return method + " " + resource + " " + version
348 |
349 | # Generate the HTTP code field for the access line
350 | def get_code(self):
351 | return self.config["code"]
352 |
353 | # Generate the message size field for the access line
354 | def get_size(self):
355 | return random.randint(1024, 10240)
356 |
357 |
358 | def get_access_sleep_time(self):
359 | # 'normal' mode - uniform distribution between min & max intervals
360 | if self.mode == 'uniform':
361 | return random.uniform(self.access_interval[0], self.access_interval[1])
362 | # 'push' mode - at highest rate
363 | elif self.mode == 'push':
364 | return self.access_interval[0]
365 |
366 | # 'spike' mode
367 | elif self.mode == 'spike':
368 | mean = (self.access_interval[0]+self.access_interval[1])/2
369 | # Standard deviation
370 | sigma = (self.access_interval[1]-self.access_interval[0])/2
371 | return numpy.random.normal(mean, sigma)
372 |
373 | else:
374 | random.uniform(self.access_interval[0], self.access_interval[1])
375 |
376 |
377 |
378 |
379 |
--------------------------------------------------------------------------------
/src/base_generator.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | #################################
5 | ##
6 | ## Abstract Base Log Generator
7 | ##
8 | #################################
9 | class log_gen(metaclass=abc.ABCMeta):
10 |
11 | @abc.abstractproperty
12 | def lines(self):
13 | pass
14 |
15 | @abc.abstractproperty
16 | def methods(self):
17 | pass
18 |
19 | @abc.abstractproperty
20 | def methods_p(self):
21 | pass
22 |
23 | @abc.abstractproperty
24 | def mode(self):
25 | pass
26 |
27 | @abc.abstractproperty
28 | def out_format(self):
29 | pass
30 |
31 | @abc.abstractmethod
32 | def run(self):
33 | pass
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/tests/log_generator_test.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from .. import log_gen
3 | from .. import apache_gen
4 | import asyncio
5 | from asyncio import coroutine
6 | import os
7 | import re
8 | import json
9 |
10 | ##########################################
11 | #####
12 | ##### Test Abstract Class
13 | #####
14 | ##########################################
15 | def test_abstract_class():
16 |
17 | try:
18 | gen = log_gen()
19 | assert False, 'Abstract class instance created!'
20 | except TypeError:
21 | pass
22 |
23 | try:
24 | class one_log_gen(log_gen):
25 | @property
26 | def methods(self):
27 | pass
28 | @property
29 | def methods_p(self):
30 | pass
31 | @property
32 | def mode(self):
33 | pass
34 | @property
35 | def out_format(self):
36 | pass
37 | def run(self):
38 | pass
39 | gen = one_log_gen()
40 | assert False, "Abstract class property not implemented"
41 | except TypeError:
42 | pass
43 |
44 | try:
45 | class one_log_gen(log_gen):
46 | @property
47 | def lines(self):
48 | pass
49 | @property
50 | def method(self):
51 | pass
52 | @property
53 | def methods_p(self):
54 | pass
55 | @property
56 | def mode(self):
57 | pass
58 | @property
59 | def out_format(self):
60 | pass
61 | gen = one_log_gen()
62 | assert False, "Abstract class method not implemented"
63 | except TypeError:
64 | pass
65 |
66 | ##########################################
67 | #####
68 | ##### Test Apache Attribute Setting
69 | #####
70 | ##########################################
71 |
72 | def test_attr_lines():
73 | gen = apache_gen()
74 | with pytest.raises(Exception) as error_info:
75 | gen.lines = set('access')
76 | assert str(error_info.value) == 'lines should be a list.'
77 |
78 | with pytest.raises(Exception) as error_info:
79 | gen.lines = ['whatever']
80 | assert str(error_info.value) == "Unsupported line types."
81 |
82 | with pytest.raises(Exception) as error_info:
83 | gen.lines = ['access', 'access']
84 | assert str(error_info.value) == "Duplicated line types."
85 |
86 |
87 | def test_attr_methods():
88 | gen = apache_gen()
89 | with pytest.raises(Exception) as error_info:
90 | gen.methods = set(['GET', 'POP', 'PUT', 'DELETE'])
91 | assert str(error_info.value) == 'methods should be a list.'
92 |
93 | with pytest.raises(Exception) as error_info:
94 | gen.methods = ['GET', 'POP', 'PUT', 'DELETE']
95 | assert str(error_info.value) == "Unsupported method types."
96 |
97 | with pytest.raises(Exception) as error_info:
98 | gen.methods = ['GET', 'GET', 'POST', 'PUT', 'DELETE']
99 | assert str(error_info.value) == "Duplicated method types."
100 |
101 |
102 | def test_attr_methods_p():
103 | gen = apache_gen()
104 | with pytest.raises(Exception) as error_info:
105 | gen.methods_p = set([0.6, 0.4])
106 | assert str(error_info.value) == 'methods_p should be a list.'
107 |
108 | with pytest.raises(Exception) as error_info:
109 | gen.methods = ['GET', 'POST', 'PUT', 'DELETE']
110 | gen.methods_p = [0.5, 0.5]
111 | assert str(error_info.value) == "Length of methods_p doesn't equal length of methods."
112 |
113 | with pytest.raises(Exception) as error_info:
114 | gen.methods = ['GET', 'POST', 'PUT', 'DELETE']
115 | gen.methods_p = [0.6, 0.7, 0.1, 0.1]
116 | assert str(error_info.value) == "Sum of methods_p must equals 1."
117 |
118 | with pytest.raises(Exception) as error_info:
119 | gen.methods_p = [-1, 1, 0.5, 0.5]
120 | assert str(error_info.value) == "All members of methods_p must be in the range of 0 to 1 "
121 |
122 |
123 | def test_attr_forever():
124 | gen = apache_gen()
125 | with pytest.raises(Exception) as error_info:
126 | gen.forever = 'AHA'
127 | assert str(error_info.value) == "forever must be either True or False"
128 |
129 |
130 | def test_attr_heartbeat_interval():
131 | gen = apache_gen()
132 | with pytest.raises(Exception) as error_info:
133 | gen.heartbeat_interval = '0.1'
134 | assert str(error_info.value) == "heartbeat_interval value should be either integer or decimal"
135 |
136 | with pytest.raises(Exception) as error_info:
137 | gen.lines = ['access']
138 | gen.heartbeat_interval = 0.1
139 | assert str(error_info.value) == "Only set heartbeat_interval when generate heartbeat"
140 |
141 |
142 | def test_attr_access_interval():
143 | gen = apache_gen()
144 | with pytest.raises(Exception) as error_info:
145 | gen.access_interval = 1
146 | assert str(error_info.value) == "access_interval should be a list"
147 |
148 | with pytest.raises(Exception) as error_info:
149 | gen.access_interval = set([1,2])
150 | assert str(error_info.value) == "access_interval should be a list"
151 |
152 | with pytest.raises(Exception) as error_info:
153 | gen.access_interval = [1]
154 | assert str(error_info.value) == "access_interval should be a list containing 2 elements"
155 |
156 | with pytest.raises(Exception) as error_info:
157 | gen.access_interval = ['1', 2]
158 | assert str(error_info.value) == "access_interval[0] should be either integer or decimal"
159 |
160 | with pytest.raises(Exception) as error_info:
161 | gen.access_interval = [1, '2']
162 | assert str(error_info.value) == "access_interval[1] should be either integer or decimal"
163 |
164 | with pytest.raises(Exception) as error_info:
165 | gen.access_interval = [2, 1]
166 | assert str(error_info.value) == "access_interval[0] should be smaller than access_interval[1]"
167 |
168 |
169 | def test_attr_mode():
170 | gen = apache_gen()
171 | with pytest.raises(Exception) as error_info:
172 | gen.mode = 'drama'
173 | assert str(error_info.value) == "Unrecognized mode"
174 |
175 |
176 | def test_attr_out_format():
177 | gen = apache_gen()
178 | with pytest.raises(Exception) as error_info:
179 | gen.out_format = 'log'
180 | assert str(error_info.value) == "out_format should be a list"
181 |
182 | with pytest.raises(Exception) as error_info:
183 | gen.out_format = []
184 | assert str(error_info.value) == "Should select at least 1 output format"
185 |
186 | with pytest.raises(Exception) as error_info:
187 | gen.out_format = ['stdout', 'cat']
188 | assert str(error_info.value) == "Unsupported output format"
189 |
190 |
191 | def test_attr_rotation():
192 | gen = apache_gen()
193 | with pytest.raises(Exception) as error_info:
194 | gen.rotation = 'true'
195 | assert str(error_info.value) == "rotation must be either True or False"
196 |
197 |
198 | def test_attr_rotation_size():
199 | gen = apache_gen()
200 | with pytest.raises(Exception) as error_info:
201 | gen.rotation_size = 76.9
202 | assert str(error_info.value) == "rotation_size must be an integer"
203 |
204 |
205 | #def test_attr_out_log():
206 | # gen = apache_gen()
207 | # with pytest.raises(Exception) as error_info:
208 | # gen.out_log = 'XXXOHA'
209 | # assert str(error_info.value) == "Invalid output path"
210 |
211 | ##########################################
212 | #####
213 | ##### Test Log Field Generation Methods
214 | #####
215 | ##########################################
216 | def test_get_time_field():
217 | gen = apache_gen()
218 | try:
219 | time_field = gen.get_time_field().split()
220 | time_field0 = time_field[0]
221 | time_field1 = time_field[1]
222 | assert time_field1 == '-0700'
223 | assert len(time_field0.split('/')) == 3
224 | except:
225 | assert False
226 |
227 |
228 | def test_get_ip():
229 | gen = apache_gen()
230 | try:
231 | ip = gen.get_ip()
232 | assert len(ip.split('.')) == 4
233 | for x in ip.split('.'):
234 | assert int(x) in range(0, 256)
235 | except:
236 | assert False
237 |
238 |
239 | def test_get_user_identifier():
240 | gen = apache_gen()
241 | try:
242 | user_identifier = gen.get_user_identifier()
243 | assert user_identifier == '-'
244 | except:
245 | assert False
246 |
247 |
248 | def test_get_user_id():
249 | gen = apache_gen()
250 | config_file = './config/apache_gen.json'
251 | with open(config_file, 'r') as f:
252 | config = json.load(f)
253 | try:
254 | user_id = gen.get_user_id()
255 | assert user_id in config["user_id"]
256 | except:
257 | assert False
258 |
259 |
260 | def test_get_method():
261 | gen = apache_gen()
262 | try:
263 | method = gen.get_method()
264 | assert method in ['GET', 'POST', 'PUT', 'DELETE']
265 | except:
266 | assert False
267 |
268 |
269 | def test_get_resource():
270 | gen = apache_gen()
271 | try:
272 | resource = gen.get_resource()
273 | assert resource == '/apache_pb.gif'
274 | except:
275 | assert False
276 |
277 |
278 | def test_get_version():
279 | gen = apache_gen()
280 | try:
281 | version = gen.get_version()
282 | assert version == 'HTTP/1.0'
283 | except:
284 | assert False
285 |
286 |
287 | def test_get_msg():
288 | gen = apache_gen()
289 | try:
290 | msg = gen.get_msg('a', 'b', 'c')
291 | assert msg == 'a b c'
292 | except:
293 | assert False
294 |
295 |
296 | def test_get_code():
297 | gen = apache_gen()
298 | try:
299 | code = gen.get_code()
300 | assert code == '200'
301 | except:
302 | assert False
303 |
304 |
305 | def test_get_size():
306 | gen = apache_gen()
307 | try:
308 | size = gen.get_size()
309 | assert size in range(1024, 10241)
310 | except:
311 | assert False
312 |
313 |
314 | ##########################################
315 | #####
316 | ##### Test Log Generation Results
317 | #####
318 | ##########################################
319 | def test_heartbeat_lines_format():
320 | gen = apache_gen(out_path='./test_heartbeat_lines_format.txt', forever=False, count=1)
321 | gen.lines = ['heartbeat']
322 | gen.run()
323 |
324 | try:
325 | f = open('./test_heartbeat_lines_format.txt')
326 | line = f.readlines()[0]
327 | # Extract the time field
328 | log_time = re.findall(r'\[(.*?)\]', line)
329 | assert len(log_time) == 1
330 | # Extract the message field
331 | log_msg = re.findall(r'\"(.*?)\"', line)
332 | assert len(log_msg) == 1
333 | assert log_msg[0] == 'HEARTBEAT'
334 | except:
335 | assert False
336 |
337 |
338 | def test_access_lines_format():
339 | gen = apache_gen(out_path='./test_access_lines_format.txt', forever=False, count=1)
340 | gen.lines = ['access']
341 | gen.run()
342 |
343 | try:
344 | f = open('./test_access_lines_format.txt')
345 | line = f.readlines()[0]
346 | # Extract the time field
347 | log_time = re.findall(r'\[(.*?)\]', line)
348 | assert len(log_time) == 1
349 | # Extract the message field
350 | log_msg = re.findall(r'\"(.*?)\"', line)
351 | assert len(log_msg) == 1
352 |
353 | except:
354 | assert False
355 |
356 |
357 | def test_count_control():
358 | gen = apache_gen(out_path='./test_count_control.txt', forever=False, count=3)
359 | gen.lines = ['heartbeat']
360 | gen.run()
361 |
362 | try:
363 | f = open('./test_count_control.txt')
364 | lines = f.readlines()
365 | assert len(lines) == 3
366 | except:
367 | assert False
368 |
369 |
370 | def test_rotation():
371 | gen = apache_gen(out_path='./test_rotation.txt', forever=False, count=10)
372 | gen.rotation_size = 10
373 | gen.lines = ['heartbeat', 'access']
374 | gen.run()
375 | assert gen.rotation_size == 10
376 | assert gen.out_log == './test_rotation.txt.9'
377 |
378 | # Test param: lines
379 | '''def test_lines_control():
380 | gen = apache_gen(out_path='./test_lines_control.txt', lines=['heartbeat', 'access'], methods=['GET', 'PUT', 'POST', 'DELETE'], forever=False, count=10)
381 | gen.run()
382 |
383 | lines_li = set()
384 |
385 | try:
386 | f = open('./test_lines_control.txt')
387 | lines = f.readlines()
388 | for line in lines:
389 | # Extract the message field
390 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
391 | if log_msg == 'HEARTBEAT':
392 | lines_li.add('heartbeat')
393 | else:
394 | log_method = log_msg.split()[0]
395 | if log_method in ['GET', 'PUT', 'POST', 'DELETE']:
396 | lines_li.add('access')
397 |
398 | assert lines_li == set(['heartbeat', 'access'])
399 |
400 | except:
401 | assert False
402 |
403 |
404 | # Test param: methods
405 | def test_access_lines_method():
406 | # Test GET generation
407 | gen = apache_gen(out_path='./test_access_lines_method.txt', lines=['access'], methods=['GET'], forever=False, count=3)
408 | gen.run()
409 |
410 | try:
411 | f = open('./test_access_lines_method.txt')
412 | lines = f.readlines()
413 | for line in lines:
414 | # Extract the message field
415 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
416 | # Extract the http method
417 | log_method = log_msg.split()[0]
418 | assert log_method == 'GET'
419 |
420 | except:
421 | assert False
422 |
423 | # Test PUT generation
424 | gen = apache_gen(out_path='./test_access_lines_method.txt', lines=['access'], methods=['PUT'], forever=False, count=3)
425 | gen.run()
426 |
427 | try:
428 | f = open('./test_access_lines_method.txt')
429 | lines = f.readlines()
430 | for line in lines:
431 | # Extract the message field
432 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
433 | # Extract the http method
434 | log_method = log_msg.split()[0]
435 | assert log_method == 'PUT'
436 |
437 | except:
438 | assert False
439 |
440 | # Test POST generation
441 | gen = apache_gen(out_path='./test_access_lines_method.txt', lines=['access'], methods=['POST'], forever=False, count=3)
442 | gen.run()
443 |
444 | try:
445 | f = open('./test_access_lines_method.txt')
446 | lines = f.readlines()
447 | for line in lines:
448 | # Extract the message field
449 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
450 | # Extract the http method
451 | log_method = log_msg.split()[0]
452 | assert log_method == 'POST'
453 | except:
454 | assert False
455 |
456 | # Test DELETE generation
457 | gen = apache_genout_path='./test_access_lines_method.txt', lines=['access'], methods=['DELETE'], forever=False, count=3)
458 | gen.run()
459 |
460 | try:
461 | f = open('./test_access_lines_method.txt')
462 | lines = f.readlines()
463 | for line in lines:
464 | # Extract the message field
465 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
466 | # Extract the http method
467 | log_method = log_msg.split()[0]
468 | assert log_method == 'DELETE'
469 | except:
470 | assert False
471 |
472 | # Test param: methods_p
473 | def test_access_lines_method_dist():
474 | gen = apache_gen(out_path='./test_access_lines_method_dist.txt', lines=['access'], methods=['GET', 'POST', 'PUT', 'DELETE'], methods_p=[1.0, 0, 0, 0], forever=False, count=3)
475 | gen.run()
476 |
477 | try:
478 | f = open('./test_access_lines_method_dist.txt')
479 | lines = f.readlines()
480 | for line in lines:
481 | # Extract the message field
482 | log_msg = re.findall(r'\"(.*?)\"', line)[0]
483 | # Extract the http method
484 | log_method = log_msg.split()[0]
485 | assert log_method == 'GET'
486 | except:
487 | assert False
488 | '''
489 |
490 |
491 |
492 |
--------------------------------------------------------------------------------