├── .gitignore
├── .manifest
├── .travis.yml
├── DEVELOPMENT.md
├── LICENSE
├── Makefile
├── README.md
├── dialyzer.ignore-warnings
├── doc
└── overview.edoc
├── priv
├── ForkMe_Blk.png
├── doctorbasho.jpg
├── edoc.css
└── index.html
├── rebar
├── rebar.config
└── src
├── riaknostic.app.src
├── riaknostic.erl
├── riaknostic_check.erl
├── riaknostic_check_disk.erl
├── riaknostic_check_dumps.erl
├── riaknostic_check_memory_use.erl
├── riaknostic_check_monitors.erl
├── riaknostic_check_nodes_connected.erl
├── riaknostic_check_ring_membership.erl
├── riaknostic_check_ring_preflists.erl
├── riaknostic_check_ring_size.erl
├── riaknostic_check_search.erl
├── riaknostic_check_strong_consistency.erl
├── riaknostic_config.erl
├── riaknostic_node.erl
└── riaknostic_util.erl
/.gitignore:
--------------------------------------------------------------------------------
1 | doc/
2 | deps/
3 | ebin/*
4 | log/
5 | edoc/
6 | index.html
7 | riaknostic
8 | *.png
9 | pkg/
10 | erl_crash.dump
11 | .eunit/
12 | *~
13 | #*#
--------------------------------------------------------------------------------
/.manifest:
--------------------------------------------------------------------------------
1 | src
2 | riaknostic
3 | doc
4 | LICENSE
5 | README.md
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: erlang
2 | notifications:
3 | disabled: true
4 | env:
5 | - R15B
6 | - R14B04
7 | - R14B03
8 | - R14B02
9 |
--------------------------------------------------------------------------------
/DEVELOPMENT.md:
--------------------------------------------------------------------------------
1 | # Riaknostic Development
2 |
3 | Riaknostic requires a sane GNU build system and a recent version of
4 | Erlang. It has `lager` and `getopt` as dependencies, so those must be
5 | compatible with your version of Erlang. Release versions are currently
6 | built with Erlang version R14B03, while development versions are targeted at Erlang version R14B04.
7 |
8 | See the `rebar.config` file for more details.
9 |
10 | To build Riaknostic, simply run `make`:
11 |
12 | ```bash
13 | $ make
14 | ./rebar get-deps
15 | ==> riaknostic (get-deps)
16 | Pulling lager from {git,"git://github.com/basho/lager",{branch,"master"}}
17 | Cloning into lager...
18 | Pulling getopt from {git,"git://github.com/jcomellas/getopt.git","2981dfe"}
19 | Cloning into getopt...
20 | ==> lager (get-deps)
21 | ==> getopt (get-deps)
22 | ./rebar compile
23 | ==> lager (compile)
24 | Compiled src/lager_util.erl
25 | Compiled src/lager_transform.erl
26 | Compiled src/lager_sup.erl
27 | Compiled src/lager_mochiglobal.erl
28 | Compiled src/lager_stdlib.erl
29 | Compiled src/lager_handler_watcher_sup.erl
30 | Compiled src/lager_handler_watcher.erl
31 | Compiled src/lager_trunc_io.erl
32 | Compiled src/lager_crash_log.erl
33 | Compiled src/lager_file_backend.erl
34 | Compiled src/lager_app.erl
35 | Compiled src/lager.erl
36 | Compiled src/lager_console_backend.erl
37 | Compiled src/lager_format.erl
38 | Compiled src/error_logger_lager_h.erl
39 | ==> getopt (compile)
40 | Compiled src/getopt.erl
41 | ==> riaknostic (compile)
42 | Compiled src/riaknostic_check.erl
43 | Compiled src/riaknostic_util.erl
44 | Compiled src/riaknostic_node.erl
45 | Compiled src/riaknostic_check_ring_size.erl
46 | Compiled src/riaknostic_check_ring_membership.erl
47 | Compiled src/riaknostic_config.erl
48 | Compiled src/riaknostic_check_memory_use.erl
49 | Compiled src/riaknostic_check_nodes_connected.erl
50 | Compiled src/riaknostic_check_dumps.erl
51 | Compiled src/riaknostic.erl
52 | Compiled src/riaknostic_check_disk.erl
53 | ./rebar escriptize
54 | ==> lager (escriptize)
55 | ==> getopt (escriptize)
56 | ==> riaknostic (escriptize)
57 | ```
58 |
59 | Now you can invoke the script manually via the below command:
60 |
61 | ```bash
62 | $ ./riaknostic --etc ~/code/riak/rel/riak/etc --base ~/code/riak/rel/riak --user `whoami` [other options]
63 | ```
64 |
65 | To generate the edoc reference, use `make docs` and then open the
66 | `doc/index.html` file in your browser. Detailed discussion of the
67 | internal APIs that you can use in developing new diagnostics is found
68 | in the edocs.
69 |
70 | ## Contributing
71 |
72 | Have an idea for a diagnostic? Want to improve the way Riaknostic works? Fork the [github repository](https://github.com/basho/riaknostic) and send us a pull-request with your changes! The code is documented with `edoc`, so give the [API Docs](http://riaknostic.basho.com/edoc/index.html) a read before you contribute.
73 |
74 | ### Developing for Riaknostic Without a Riak Instance
75 |
76 | If you want to run the `riaknostic` script while developing, and you don't have it hooked up to your local Riak, you can invoke it directly like so:
77 |
78 | ```bash
79 | ./riaknostic --etc ~/code/riak/rel/riak/etc --base ~/code/riak/rel/riak --user `whoami` [other options]
80 | ```
81 |
82 | The extra options are usually assigned by the `riak-admin` script for you, but here's how to set them:
83 |
84 | * `--etc`: Where your Riak configuration directory is, in the example above it's in the generated directory of a source checkout of Riak.
85 | * `--base`: The "base" directory of Riak, usually the root of the generated directory or `/usr/lib/riak` on Linux, for example. Scan the `riak-admin` script for how the `RUNNER_BASE_DIR` variable is assigned on your platform.
86 | * `--user`: What user/UID the Riak node runs as. In a source checkout, it's the current user, on most systems, it's `riak`.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: rel stagedevrel deps test
2 |
3 | all: deps compile
4 |
5 | compile:
6 | ./rebar compile
7 |
8 | deps:
9 | ./rebar get-deps
10 |
11 | clean:
12 | ./rebar clean
13 |
14 | distclean: clean
15 | ./rebar delete-deps
16 |
17 | test:
18 | ./rebar compile eunit
19 |
20 | escriptize:
21 | ./rebar escriptize
22 |
23 | ##
24 | ## Doc targets
25 | ##
26 | docs:
27 | ./rebar doc skip_deps=true
28 |
29 | pages: docs
30 | cp priv/index.html doc/_index.html
31 | cp priv/ForkMe_Blk.png doc/
32 | cp priv/*.jpg doc/
33 | git checkout gh-pages
34 | mv doc/_index.html ./index.html
35 | mv doc/ForkMe_Blk.png .
36 | mv doc/*.jpg .
37 | rm -rf edoc/*
38 | cp -R doc/* edoc/
39 | git add .
40 | git add -u
41 | git commit
42 | git push origin gh-pages
43 | git checkout master
44 |
45 | ##
46 | ## Release targets
47 | ##
48 | VSN = `grep vsn src/riaknostic.app.src | cut -f 2 -d "\""`
49 |
50 | package: all docs
51 | @mkdir -p pkg/riaknostic
52 | @rm -rf pkg/riaknostic/*
53 | @cat .manifest | xargs -n 1 -I % cp -R % pkg/riaknostic/.
54 | @tar -czf pkg/riaknostic-$(VSN).tar.gz -C pkg riaknostic
55 |
56 | ##
57 | ## Dialyzer targets
58 | ##
59 | APPS = kernel stdlib sasl erts ssl tools os_mon runtime_tools crypto inets \
60 | xmerl webtool snmp public_key mnesia eunit syntax_tools compiler
61 | COMBO_PLT = $(HOME)/.riak_combo_dialyzer_plt
62 |
63 | check_plt: compile
64 | dialyzer --check_plt --plt $(COMBO_PLT) --apps $(APPS)
65 |
66 | build_plt: compile
67 | dialyzer --build_plt --output_plt $(COMBO_PLT) --apps $(APPS)
68 |
69 | dialyzer: compile
70 | @echo
71 | @echo Use "'make check_plt'" to check PLT prior to using this target.
72 | @echo Use "'make build_plt'" to build PLT prior to using this target.
73 | @echo
74 | @sleep 1
75 | dialyzer -Wno_return --plt $(COMBO_PLT) ebin deps/*/ebin | \
76 | fgrep -v -f ./dialyzer.ignore-warnings
77 |
78 | cleanplt:
79 | @echo
80 | @echo "Are you sure? It takes about 1/2 hour to re-build."
81 | @echo Deleting $(COMBO_PLT) in 5 seconds.
82 | @echo
83 | sleep 5
84 | rm $(COMBO_PLT)
85 |
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Riaknostic [](http://travis-ci.org/basho/riaknostic)
2 |
3 | `riaknostic` is an escript and set of tools that diagnoses common problems which could affect a Riak node or cluster. When experiencing any problem with Riak, `riaknostic` should be the first thing run during troubleshooting. The tool is integrated with Riak via the `riak-admin` script.
4 |
5 | ## Overview
6 |
7 | To diagnose problems with Riak, Riaknostic uses a series of checks which are derived from the experience of the Basho Client Services Team as well as numerous public discussions on the mailing list, IRC room, and other online media.
8 |
9 | Here is a basic example of using `riaknostic` followed immediately by the command's output:
10 |
11 | ```bash
12 | $ riak-admin diag
13 | 15:34:52.736 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving
14 | crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
15 | 15:34:52.736 [notice] Data directory /srv/riak/data/bitcask is not mounted with 'noatime'. Please remount its disk with the 'noatime' flag to improve
16 | performance.
17 | ```
18 |
19 | As shown in the above output, Riaknostic tells us about two problems right away. First, an Erlang crash dump is present, indicating that Riak has experienced a crash. Second, a performance problem is mentioned (disk mounted without `noatime` argument)along with a helpful tip to resolve the issue.
20 |
21 | ## Installation
22 |
23 | **Important**: If you are running Riak v1.3.0 or greater, you already have Riaknostic, so you can skip to the **Usage** section below.
24 |
25 | Riaknostic depends on features introduced by Erlang version R14B04, so verify that you've installed this version of Erlang before proceeding with installation.
26 |
27 | To install `riaknostic`, download the latest package version, and extract it within the directory shown for your operating system in the following table:
28 |
29 |
30 |
31 |
Platform
Directory
32 |
33 |
34 |
35 |
Linux (Redhat, CentOS, Debian, Ubuntu)
36 |
/usr/lib/riak/lib
37 |
38 |
39 |
Linux (Fedora)
40 |
/usr/lib64/riak/lib
41 |
42 |
43 |
Solaris, OpenSolaris
44 |
/opt/riak/lib
45 |
46 |
47 |
SmartOS (Joyent)
48 |
/opt/local/lib/riak/lib
49 |
50 |
51 |
Mac OS/X or Self-built
52 |
$RIAK/lib
53 | (where $RIAK=rel/riak for source installs,
54 | or the directory where you unpacked the package)
55 |
56 |
57 |
58 |
59 | An example Riaknostic installation for Linux looks like this:
60 |
61 | ```bash
62 | wget https://github.com/basho/riaknostic/downloads/riaknostic-1.0.2.tar.gz -P /tmp
63 | cd /usr/lib/riak/lib
64 | sudo tar xzvf /tmp/riaknostic-1.0.2.tar.gz
65 | ```
66 |
67 | The package will expand to a `riaknostic/` directory which contains the `riaknostic` script, source code in the `src/` directory, and documentation.
68 |
69 | Now try it out!
70 |
71 | ## Usage
72 |
73 | For most cases, you can just run the `riak-admin diag` command as given at the top of this README. However, sometimes you might want to know some extra detail or run only specific checks. For that, there are command-line options. Execute `riaknostic --help` to learn more about these options:
74 |
75 | ```bash
76 | riak-admin diag --help
77 | Usage: riak-admin diag [-d ] [-l] [-h] [check_name ...]
78 |
79 | -d, --level Minimum message severity level (default: notice)
80 | -l, --list Describe available diagnostic tasks
81 | -h, --help Display help/usage
82 | check_name A specific check to run
83 | ```
84 |
85 | To get an idea of what checks will be run, use the `--list` option:
86 |
87 | ```bash
88 | riak-admin diag --list
89 | Available diagnostic checks:
90 |
91 | disk Data directory permissions and atime
92 | dumps Find crash dumps
93 | memory_use Measure memory usage
94 | nodes_connected Cluster node liveness
95 | ring_membership Cluster membership validity
96 | ring_size Ring size valid
97 | ```
98 |
99 | If you want all the gory details about what Riaknostic is doing, you can run the checks at a more verbose logging level with the --level option:
100 |
101 | ```bash
102 | riak-admin diag --level debug
103 | 18:34:19.708 [debug] Lager installed handler lager_console_backend into lager_event
104 | 18:34:19.720 [debug] Lager installed handler error_logger_lager_h into error_logger
105 | 18:34:19.720 [info] Application lager started on node nonode@nohost
106 | 18:34:20.736 [debug] Not connected to the local Riak node, trying to connect. alive:false connect_failed:undefined
107 | 18:34:20.737 [debug] Starting distributed Erlang.
108 | 18:34:20.740 [debug] Supervisor net_sup started erl_epmd:start_link() at pid <0.42.0>
109 | 18:34:20.742 [debug] Supervisor net_sup started auth:start_link() at pid <0.43.0>
110 | 18:34:20.771 [debug] Supervisor net_sup started net_kernel:start_link(['riak_diag87813@127.0.0.1',longnames]) at pid <0.44.0>
111 | 18:34:20.771 [debug] Supervisor kernel_sup started erl_distribution:start_link(['riak_diag87813@127.0.0.1',longnames]) at pid <0.41.0>
112 | 18:34:20.781 [debug] Supervisor inet_gethost_native_sup started undefined at pid <0.49.0>
113 | 18:34:20.782 [debug] Supervisor kernel_safe_sup started inet_gethost_native:start_link() at pid <0.48.0>
114 | 18:34:20.834 [debug] Connected to local Riak node 'riak@127.0.0.1'.
115 | 18:34:20.939 [debug] Local RPC: os:getpid([]) [5000]
116 | 18:34:20.939 [debug] Running shell command: ps -o pmem,rss,command -p 83144
117 | 18:34:20.946 [debug] Shell command output:
118 | %MEM RSS COMMAND
119 | 0.4 31004 /srv/riak/erts-5.8.4/bin/beam.smp -K true -A 64 -W w -- -root /srv/riak/rel/riak -progname riak -- -home /Users/sean -- -boot /srv/riak/releases/1.0.2/riak -embedded -config /srv/riak/etc/app.config -name riak@127.0.0.1 -setcookie riak -- console
120 |
121 | 18:34:20.960 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
122 | 18:34:20.961 [notice] Data directory /srv/riak/data/bitcask is not mounted with 'noatime'. Please remount its disk with the 'noatime' flag to improve performance.
123 | 18:34:20.961 [info] Riak process is using 0.4% of available RAM, totalling 31004 KB of real memory.
124 | ```
125 |
126 | Most times you'll want to use the defaults, but any Syslog severity name will do (from most to least verbose): `debug, info, notice, warning, error, critical, alert, emergency`.
127 |
128 | Finally, if you want to run just a single diagnostic or a list of specific ones, you can pass their name(s):
129 |
130 | ```bash
131 | riak-admin diag dumps
132 | 18:41:24.083 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
133 | ```
134 |
135 | ## Contributing
136 |
137 | 0. Read DEVELOPMENT.md
138 | 1. Fork the project on [Github](https://github.com/basho/riaknostic).
139 | 2. Make your changes or additions on a "topic" branch, test and
140 | document them. If you are making a new diagnostic, make sure you
141 | give some module-level information about the checks it
142 | performs. *Note*: diagnostics _should not_ make modifications to
143 | Riak, only inspect things.
144 | 3. Push to your fork and send a pull-request.
145 | 4. A Basho Developer Advocate or Engineer will review your
146 | pull-request and get back to you.
147 |
--------------------------------------------------------------------------------
/dialyzer.ignore-warnings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/basho/riaknostic/dad8939d0ef32fbf435d13697720223293195282/dialyzer.ignore-warnings
--------------------------------------------------------------------------------
/doc/overview.edoc:
--------------------------------------------------------------------------------
1 | @author Basho Technologies, Inc.
2 | @copyright 2011 Basho Technologies, Inc.
3 | @version 1.0.0
4 | @title riaknostic: Automated diagnostic tools for Riak
5 | @doc
riaknostic is an escript and set of tools that diagnoses common problems which could affect a Riak node or cluster. When experiencing any problem with Riak, riaknostic should be the first thing run during troubleshooting. The tool is integrated with Riak via the riak-admin script.
6 |
7 |
$ riak-admin diag
8 |
9 |
This documentation describes the riaknostic API and user interface commands. The application's core consists of 5 modules:
10 |
11 |
12 |
riaknostic - the core of the script, including CLI parsing and dispatching commands.
13 |
riaknostic_check - the behaviour module that all diagnostics must implement, including some general
14 | functions that support the riaknostic module.
15 |
riaknostic_config - convenience functions for inspecting the configuration of the local Riak node.
16 |
riaknostic_node - functions for sending commands to or inspecting the local Riak node or all members of the cluster.
17 |
riaknostic_util - utility functions, including for running shell programs
18 |
19 |
20 |
All other included modules are generally prefixed with riaknostic_check_ and are individual diagnostics that can be run.
21 |
22 |
riaknostic is licensed under the Apache v2 license.
Sometimes, things go wrong in Riak. How can you know what's
28 | wrong? Riaknostic is here to help.
29 |
$ riak-admin diag
30 | 15:34:52.736 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
31 | 15:34:52.736 [notice] Data directory /srv/riak/data/bitcask is not mounted with 'noatime'. Please remount its disk with the 'noatime' flag to improve performance.
32 |
Riaknostic, which is invoked via the above command, is a
33 | small suite of diagnostic checks that can be run against
34 | your Riak node to discover common problems and recommend how
35 | to resolve them. These checks are derived from the experience
36 | of the Basho Client Services Team as well as numerous
37 | public discussions on the mailing list, IRC room, and other
38 | online media.
39 |
40 |
41 |
42 |
43 |
Installation
44 |
After downloading the package, expand it in the directory below according to
45 | your platform:
46 |
47 |
48 |
Platform
Directory
49 |
50 |
51 |
52 |
Linux (Redhat, CentOS, Debian, Ubuntu)
53 |
/usr/lib/riak/lib
54 |
55 |
56 |
Linux (Fedora)
57 |
/usr/lib64/riak/lib
58 |
59 |
60 |
Solaris, OpenSolaris
61 |
/opt/riak/lib
62 |
63 |
64 |
Mac OS/X or Self-built
65 |
$RIAK/lib
66 | (where $RIAK=rel/riak for source installs,
67 | or the directory where you unpacked the package)
68 |
69 |
70 |
71 |
For example, on Linux, I might do this:
72 |
$ wget https://github.com/basho/riaknostic/downloads/riaknostic-1.0.1.tar.gz -P /tmp
73 | $ cd /usr/lib/riak/lib
74 | $ sudo tar xzvf /tmp/riaknostic-1.0.1.tar.gz
75 |
The package will expand to a riaknostic/
76 | directory which contains the riaknostic script,
77 | source code in the src/ directory and
78 | documentation. Now try it out!
79 |
80 |
81 |
Usage
82 |
For most cases, you can just run the riak-admin
83 | diag command as given at the top of the
84 | page. However, sometimes you might want to know some extra
85 | detail or run only specific checks. For that, there are
86 | command-line options. Add --help to get the options:
87 |
$ riak-admin diag --help
88 | Usage: riak-admin diag [-d <level>] [-l] [-h] [check_name ...]
89 |
90 | -d, --level Minimum message severity level (default: notice)
91 | -l, --list Describe available diagnostic tasks
92 | -h, --help Display help/usage
93 | check_name A specific check to run
94 |
To get an idea of what checks will be run, use
95 | the --list option:
96 |
$ riak-admin diag --list
97 | Available diagnostic checks:
98 |
99 | disk Data directory permissions and atime
100 | dumps Find crash dumps
101 | memory_use Measure memory usage
102 | nodes_connected Cluster node liveness
103 | ring_membership Cluster membership validity
104 | ring_size Ring size valid
105 |
If you want all the gory details about what Riaknostic is
106 | doing, you can run the checks at a more verbose logging
107 | level with the --level option:
108 |
$ riak-admin diag --level debug
109 | 18:34:19.708 [debug] Lager installed handler lager_console_backend into lager_event
110 | 18:34:19.720 [debug] Lager installed handler error_logger_lager_h into error_logger
111 | 18:34:19.720 [info] Application lager started on node nonode@nohost
112 | 18:34:20.736 [debug] Not connected to the local Riak node, trying to connect. alive:false connect_failed:undefined
113 | 18:34:20.737 [debug] Starting distributed Erlang.
114 | 18:34:20.740 [debug] Supervisor net_sup started erl_epmd:start_link() at pid <0.42.0>
115 | 18:34:20.742 [debug] Supervisor net_sup started auth:start_link() at pid <0.43.0>
116 | 18:34:20.771 [debug] Supervisor net_sup started net_kernel:start_link(['riak_diag87813@127.0.0.1',longnames]) at pid <0.44.0>
117 | 18:34:20.771 [debug] Supervisor kernel_sup started erl_distribution:start_link(['riak_diag87813@127.0.0.1',longnames]) at pid <0.41.0>
118 | 18:34:20.781 [debug] Supervisor inet_gethost_native_sup started undefined at pid <0.49.0>
119 | 18:34:20.782 [debug] Supervisor kernel_safe_sup started inet_gethost_native:start_link() at pid <0.48.0>
120 | 18:34:20.834 [debug] Connected to local Riak node 'riak@127.0.0.1'.
121 | 18:34:20.939 [debug] Local RPC: os:getpid([]) [5000]
122 | 18:34:20.939 [debug] Running shell command: ps -o pmem,rss,command -p 83144
123 | 18:34:20.946 [debug] Shell command output:
124 | %MEM RSS COMMAND
125 | 0.4 31004 /srv/riak/erts-5.8.4/bin/beam.smp -K true -A 64 -W w -- -root /srv/riak/rel/riak -progname riak -- -home /Users/sean -- -boot /srv/riak/releases/1.0.2/riak -embedded -config /srv/riak/etc/app.config -name riak@127.0.0.1 -setcookie riak -- console
126 |
127 | 18:34:20.960 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
128 | 18:34:20.961 [notice] Data directory /srv/riak/data/bitcask is not mounted with 'noatime'. Please remount its disk with the 'noatime' flag to improve performance.
129 | 18:34:20.961 [info] Riak process is using 0.4% of available RAM, totalling 31004 KB of real memory.
130 |
Most times you'll want to use the defaults, but any
131 | Syslog severity name will do (from most to least
132 | verbose): debug, info, notice, warning, error,
133 | critical, alert, emergency.
134 |
Finally, if you want to run just a single diagnostic or a list
135 | of specific ones, you can pass their name(s):
136 |
$ riak-admin diag dumps
137 | 18:41:24.083 [warning] Riak crashed at Wed, 07 Dec 2011 21:47:50 GMT, leaving crash dump in /srv/riak/log/erl_crash.dump. Please inspect or remove the file.
138 |
139 |
140 |
141 |
Contributing
142 |
Have an idea for a diagnostic? Want to improve the way
143 | Riaknostic works? Fork
144 | the github
145 | repository and send us a pull-request with your
146 | changes! The code is documented with edoc,
147 | so give the API Docs a
148 | read before you contribute.
149 |
If you want to run the riaknostic script
150 | while developing and you don't have it hooked up to your
151 | local Riak, you can invoke it directly like so:
Those extra options are usually assigned by
154 | the riak-admin script for you, but here's
155 | how to set them:
156 |
157 |
158 |
--etc
159 |
Where your Riak configuration directory is, in the
160 | example above it's in the generated directory of a
161 | source checkout of Riak.
162 |
163 |
164 |
--base
165 |
The "base" directory of Riak, usually the root of
166 | the generated directory
167 | or /usr/lib/riak on Linux, for
168 | example. Scan the riak-admin script for
169 | how the RUNNER_BASE_DIR variable is
170 | assigned on your platform.
171 |
172 |
173 |
--user
174 |
What user/UID the Riak node runs as. In a source
175 | checkout, it's the current user, on most systems,
176 | it's riak.
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/rebar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/basho/riaknostic/dad8939d0ef32fbf435d13697720223293195282/rebar
--------------------------------------------------------------------------------
/rebar.config:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | {escript_shebang, "#!/usr/bin/env escript\n"}.
24 | {escript_comment, "%% -nocookie\n"}.
25 |
26 | {erl_opts, [debug_info, {parse_transform, lager_transform}]}.
27 |
28 | {escript_incl_apps, [lager, getopt, goldrush]}.
29 |
30 | {deps, [
31 | {lager, ".*", {git, "https://github.com/basho/lager.git", {tag, "3.2.4"}}},
32 | {getopt, ".*", {git, "https://github.com/basho/getopt.git", {tag, "v0.8.2"}}},
33 | {meck, "0.8.*", {git, "https://github.com/basho/meck.git", {tag, "0.8.2"}}}
34 | ]}.
35 |
36 | {edoc_opts, [{stylesheet_file, "priv/edoc.css"}]}.
37 |
--------------------------------------------------------------------------------
/src/riaknostic.app.src:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 | {application, riaknostic,
23 | [
24 | {description, "Diagnostic tools for Riak"},
25 | {vsn, git},
26 | {registered, []},
27 | {applications, [
28 | kernel,
29 | stdlib,
30 | inets,
31 | lager
32 | ]},
33 | {mod, { riaknostic_app, []}}
34 | ]}.
35 |
--------------------------------------------------------------------------------
/src/riaknostic.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc
The riaknostic module is the entry point for
24 | %% the escript. It is responsible for parsing command-line arguments
25 | %% and switches, printing the available checks, listing the help text,
26 | %% or running all or the specified checks, depending on the command
27 | %% line.
28 | %%
29 | %%
The getopt application and module is used
30 | %% for command-line parsing. The defined switches and arguments are:
31 | %%
$ ./riaknostic --etc etc --base base --user user [-d level] [-l] [-h] [check_name...]
32 | %%
33 | %%
34 | %%
--etc etc
the location of the Riak
35 | %% configuration directory (set automatically by
36 | %% riak-admin)
37 | %%
--base base
the base directory of
38 | %% Riak, aka RUNNER_BASE_DIR (set automatically by
39 | %% riak-admin)
40 | %%
--user user
the user that Riak runs as
41 | %% (set automatically by riak-admin)
42 | %%
-d, --level level
the severity of
43 | %% messages you want to see, defaulting to 'notice'. Equivalent to
44 | %% syslog/lager severity levels.
45 | %%
-l, --list
lists available checks,
46 | %% that is, modules that implement riaknostic_check. A
47 | %% "short name" will be given for ease-of-use.
48 | %%
-h, --help
- print command usage
49 | %% ("help")
50 | %%
check_name
when given, a specific
51 | %% check or list of checks to run
52 | %%
53 | %% @end
54 | -module(riaknostic).
55 | -export([main/1]).
56 |
57 | -include_lib("lager/include/lager.hrl").
58 |
59 | -define(OPTS, [
60 | {etc, undefined, "etc", string, undefined },
61 | {base, undefined, "base", string, undefined },
62 | {user, undefined, "user", string, undefined },
63 | {level, $d, "level", {atom, notice}, "Minimum message severity level (default: notice)"},
64 | {list, $l, "list", undefined, "Describe available diagnostic tasks" }
65 | ]).
66 |
67 | %% @doc The main entry point for the riaknostic escript.
68 | -spec main(CommandLineArguments::[string()]) -> any().
69 | main(Args) ->
70 | application:load(riaknostic),
71 |
72 | case getopt:parse(?OPTS, Args) of
73 | {ok, {Opts, NonOptArgs}} ->
74 | case process_opts(Opts) of
75 | list -> list_checks();
76 | run -> run(NonOptArgs)
77 | end;
78 | {error, Error} ->
79 | io:format("Invalid option sequence given: ~w~n", [Error])
80 | end.
81 |
82 | list_checks() ->
83 | Descriptions = [ {riaknostic_util:short_name(Mod), Mod:description()} ||
84 | Mod <- riaknostic_check:modules() ],
85 | io:format("Available diagnostic checks:~n~n"),
86 | lists:foreach(fun({Mod, Desc}) ->
87 | io:format(" ~.20s ~s~n", [Mod, Desc])
88 | end, lists:sort(Descriptions)).
89 |
90 | run(InputChecks) ->
91 | case riaknostic_config:prepare() of
92 | {error, Reason} ->
93 | io:format("Fatal error: ~s~n", [Reason]);
94 | _ ->
95 | ok
96 | end,
97 | Checks = case InputChecks of
98 | [] ->
99 | riaknostic_check:modules();
100 | _ ->
101 | ShortNames = [{riaknostic_util:short_name(Mod), Mod} || Mod <- riaknostic_check:modules() ],
102 | element(1, lists:foldr(fun validate_checks/2, {[], ShortNames}, InputChecks))
103 | end,
104 | Messages = lists:foldl(fun(Mod, Acc) ->
105 | Acc ++ riaknostic_check:check(Mod)
106 | end, [], Checks),
107 | case Messages of
108 | [] ->
109 | io:format("No diagnostic messages to report.~n");
110 | _ ->
111 | %% Print the most critical messages first
112 | LogLevelNum = lists:foldl(
113 | fun({mask, Mask}, Acc) ->
114 | Mask bor Acc;
115 | (Level, Acc) when is_integer(Level) ->
116 | {mask, Mask} = lager_util:config_to_mask(lager_util:num_to_level(Level)),
117 | Mask bor Acc;
118 | (_, Acc) ->
119 | Acc
120 | end, 0, lager:get_loglevels(?DEFAULT_SINK)),
121 | FilteredMessages = lists:filter(fun({Level,_,_}) ->
122 | lager_util:level_to_num(Level) =< LogLevelNum
123 | end, Messages),
124 | SortedMessages = lists:sort(fun({ALevel, _, _}, {BLevel, _, _}) ->
125 | lager_util:level_to_num(ALevel) =< lager_util:level_to_num(BLevel)
126 | end, FilteredMessages),
127 | case SortedMessages of
128 | [] ->
129 | io:format("No diagnostic messages to report.~n");
130 | _ ->
131 | lists:foreach(fun riaknostic_check:print/1, SortedMessages)
132 | end
133 | end.
134 |
135 | validate_checks(Check, {Mods, SNames}) ->
136 | case lists:keyfind(Check, 1, SNames) of
137 | {Check, Mod} ->
138 | {[Mod|Mods], lists:delete({Check, Mod}, SNames)};
139 | _ ->
140 | io:format("Unknown check '~s' specified, skipping.~n", [Check]),
141 | {Mods, SNames}
142 | end.
143 |
144 | process_opts(Opts) ->
145 | process_opts(Opts, run).
146 |
147 | process_opts([], Result) ->
148 | Result;
149 | process_opts([H|T], Result) ->
150 | process_opts(T, process_option(H, Result)).
151 |
152 | process_option({etc,Path}, Result) ->
153 | application:set_env(riaknostic, etc, filename:absname(Path)),
154 | Result;
155 | process_option({base, Path}, Result) ->
156 | application:set_env(riaknostic, base, filename:absname(Path)),
157 | Result;
158 | process_option({user, User}, Result) ->
159 | application:set_env(riaknostic, user, User),
160 | Result;
161 | process_option({level, Level}, Result) ->
162 | application:set_env(riaknostic, log_level, Level),
163 | Result;
164 | process_option(list, usage) -> %% Help should have precedence over listing checks
165 | usage;
166 | process_option(list, _) ->
167 | list;
168 | process_option(usage, _) ->
169 | usage.
170 |
--------------------------------------------------------------------------------
/src/riaknostic_check.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc
Enforces a common API among all diagnostic modules and
24 | %% provides some automation around their execution.
25 | %%
Behaviour Specification
26 | %%
27 | %%
description/0
28 | %%
-spec description() -> iodata().
29 | %%
A short description of what the diagnostic does, which will be
30 | %% printed when the script is given the -l flag.
31 | %%
32 | %%
valid/0
33 | %%
-spec valid() -> boolean().
34 | %%
Whether the diagnostic is valid to run. For example, some checks
35 | %% require connectivity to the Riak node and hence call {@link
36 | %% riaknostic_node:can_connect/0. riaknostic_node:can_connect()}.
37 | %%
38 | %%
check/0
39 | %%
-spec check() -> [{lager:log_level(), term()}].
40 | %%
Runs the diagnostic, returning a list of pairs, where the first
41 | %% is a severity level and the second is any term that is understood
42 | %% by the format/1 callback.
Formats terms that were returned from check/0 for
47 | %% output to the console. Valid return values are an iolist (string,
48 | %% binary, etc) or a pair of a format string and a list of terms, as
49 | %% you would pass to {@link io:format/2. io:format/2}.
50 | %% @end
51 |
52 | -module(riaknostic_check).
53 | -export([behaviour_info/1]).
54 | -export([check/1,
55 | modules/0,
56 | print/1]).
57 |
58 | %% @doc The behaviour definition for diagnostic modules.
59 | -spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
60 | behaviour_info(callbacks) ->
61 | [{description, 0},
62 | {valid, 0},
63 | {check, 0},
64 | {format, 1}];
65 | behaviour_info(_) ->
66 | undefined.
67 |
68 | %% @doc Runs the diagnostic in the given module, if it is valid. Returns a
69 | %% list of messages that will be printed later using print/1.
70 | -spec check(Module::module()) -> [{lager:log_level(), module(), term()}].
71 | check(Module) ->
72 | case Module:valid() of
73 | true ->
74 | [ {Level, Module, Message} || {Level, Message} <- Module:check() ];
75 | _ ->
76 | []
77 | end.
78 |
79 | %% @doc Collects a list of diagnostic modules included in the
80 | %% riaknostic application.
81 | -spec modules() -> [module()].
82 | modules() ->
83 | {ok, Mods} = application:get_key(riaknostic, modules),
84 | [ M || M <- Mods,
85 | Attr <- M:module_info(attributes),
86 | {behaviour, [?MODULE]} =:= Attr orelse {behavior, [?MODULE]} =:= Attr ].
87 |
88 |
89 | %% @doc Formats and prints the given message via lager:log/3,4. The diagnostic
90 | %% module's format/1 function will be called to provide a
91 | %% human-readable message. It should return an iolist() or a 2-tuple
92 | %% consisting of a format string and a list of terms.
93 | -spec print({Level::lager:log_level(), Module::module(), Data::term()}) -> ok.
94 | print({Level, Mod, Data}) ->
95 | case Mod:format(Data) of
96 | {Format, Terms} ->
97 | riaknostic_util:log(Level, Format, Terms);
98 | String ->
99 | riaknostic_util:log(Level, String)
100 | end.
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/riaknostic_check_disk.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks permissions on data directories and
24 | %% whether noatime is set. It will only check data directories of
25 | %% known storage backends.
26 | -module(riaknostic_check_disk).
27 | -behaviour(riaknostic_check).
28 |
29 | %% The file that we will attempt to create and read under each data directory.
30 | -define(TEST_FILE, "riaknostic.tmp").
31 |
32 | %% A dependent chain of permissions checking functions.
33 | -define(CHECKPERMFUNS, [fun check_is_dir/1,
34 | fun check_is_writeable/1,
35 | fun check_is_readable/1,
36 | fun check_is_file_readable/1,
37 | fun check_atime/1]).
38 |
39 | -include_lib("kernel/include/file.hrl").
40 |
41 | -export([description/0,
42 | valid/0,
43 | check/0,
44 | format/1]).
45 |
46 | -spec description() -> string().
47 | description() ->
48 | "Data directory permissions and atime".
49 |
50 | -spec valid() -> true.
51 | valid() ->
52 | true.
53 |
54 | -spec check() -> [{lager:log_level(), term()}].
55 | check() ->
56 | DataDirs = riaknostic_config:data_directories(),
57 | %% Add additional disk checks in the function below
58 | lists:flatmap(fun(Dir) ->
59 | check_directory_permissions(Dir)
60 | end,
61 | DataDirs).
62 |
63 | -spec format(term()) -> {io:format(), [term()]}.
64 | format({disk_full, DataDir}) ->
65 | {"Disk containing data directory ~s is full! "
66 | "Please check that it is set to the correct location and that there are not "
67 | "other files using up space intended for Riak.", [DataDir]};
68 | format({no_data_dir, DataDir}) ->
69 | {"Data directory ~s does not exist. Please create it.", [DataDir]};
70 | format({no_write, DataDir}) ->
71 | User = riaknostic_config:user(),
72 | {"No write access to data directory ~s. Please make it writeable by the '~s' user.", [DataDir, User]};
73 | format({no_read, DataDir}) ->
74 | User = riaknostic_config:user(),
75 | {"No read access to data directory ~s. Please make it readable by the '~s' user.", [DataDir, User]};
76 | format({write_check, File}) ->
77 | {"Write-test file ~s is a directory! Please remove it so this test can continue.", [File]};
78 | format({atime, Dir}) ->
79 | {"Data directory ~s is not mounted with 'noatime'. "
80 | "Please remount its disk with the 'noatime' flag to improve performance.", [Dir]}.
81 |
82 | %%% Private functions
83 |
84 | check_directory_permissions(Directory) ->
85 | check_directory(Directory, ?CHECKPERMFUNS).
86 |
87 | %% Run a list of check functions against the given directory,
88 | %% returning the first non-ok result.
89 | check_directory(_, []) ->
90 | [];
91 | check_directory(Directory, [Check|Checks]) ->
92 | case Check(Directory) of
93 | ok ->
94 | check_directory(Directory, Checks);
95 | Message ->
96 | [ Message ]
97 | end.
98 |
99 | %% Check if the path is actually a directory
100 | check_is_dir(Directory) ->
101 | case filelib:is_dir(Directory) of
102 | true ->
103 | ok;
104 | _ ->
105 | {error, {no_data_dir, Directory}}
106 | end.
107 |
108 | %% Check if the directory is writeable
109 | check_is_writeable(Directory) ->
110 | File = filename:join([Directory, ?TEST_FILE]),
111 | case file:write_file(File, <<"ok">>) of
112 | ok ->
113 | ok;
114 | {error, Error} when Error == enoent orelse Error == eacces ->
115 | {error, {no_write, Directory}};
116 | {error, enospc} ->
117 | {critical, {disk_full, Directory}};
118 | {error, eisdir} ->
119 | {error, {write_check, File}}
120 | end.
121 |
122 | %% Check if the directory is readable
123 | check_is_readable(Directory) ->
124 | case file:read_file_info(Directory) of
125 | {ok, #file_info{access=Access}} when Access == read orelse
126 | Access == read_write ->
127 | ok;
128 | {error, eacces} ->
129 | {error, {no_read, Directory}};
130 | {error, Error} when Error == enoent orelse
131 | Error == enotdir ->
132 | {error, {no_data_dir, Directory}};
133 | _ ->
134 | {error, {no_read, Directory}}
135 | end.
136 |
137 | %% Check if the file we created is readable
138 | check_is_file_readable(Directory) ->
139 | File = filename:join([Directory, ?TEST_FILE]),
140 | case file:read_file(File) of
141 | {error, Error} when Error == eacces orelse
142 | Error == enotdir ->
143 | {error, {no_read, Directory}};
144 | {error, enoent} ->
145 | {error, {write_check, File}};
146 | _ -> ok
147 | end.
148 |
149 | %% Check if the directory is mounted with 'noatime'
150 | check_atime(Directory) ->
151 | File = filename:join([Directory, ?TEST_FILE]),
152 | {ok, FileInfo1} = file:read_file_info(File),
153 | timer:sleep(1001),
154 | {ok, S} = file:open(File, [read]),
155 | io:get_line(S, ''),
156 | file:close(S),
157 | {ok, FileInfo2} = file:read_file_info(File),
158 | file:delete(File),
159 | case (FileInfo1#file_info.atime =/= FileInfo2#file_info.atime) of
160 | true ->
161 | {notice, {atime, Directory}};
162 | _ ->
163 | ok
164 | end.
165 |
166 |
--------------------------------------------------------------------------------
/src/riaknostic_check_dumps.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that detects the existence of Erlang-generated
24 | %% crash dumps. It will also check whether the location that the crash
25 | %% dump is written to has correct permissions.
26 | -module(riaknostic_check_dumps).
27 | -behaviour(riaknostic_check).
28 |
29 | -include_lib("kernel/include/file.hrl").
30 |
31 | -export([description/0,
32 | valid/0,
33 | check/0,
34 | format/1]).
35 |
36 | -spec description() -> string().
37 | description() ->
38 | "Find crash dumps".
39 |
40 | -spec valid() -> true.
41 | valid() ->
42 | true.
43 |
44 | -spec check() -> [{lager:log_level(), term()}].
45 | check() ->
46 | CrashDumpConfig = riaknostic_config:get_vm_env("ERL_CRASH_DUMP"),
47 | {DumpDir, DumpFile} = case CrashDumpConfig of
48 | undefined ->
49 | Cwd = riaknostic_config:base_dir(),
50 | {Cwd, filename:absname([Cwd, "erl_crash.dump"])};
51 | File ->
52 | AbsFile = filename:absname(File, riaknostic_config:base_dir()),
53 | {filename:dirname(AbsFile), AbsFile}
54 | end,
55 | Messages = case file:read_file_info(DumpDir) of
56 | {error, enoent} ->
57 | [{error, {enoent, DumpDir}}];
58 | {error, _} ->
59 | [{error, {eacces, DumpDir}}];
60 | {ok, #file_info{access=Access}} when Access =/= read_write ->
61 | [{error, {eacces, DumpDir}}];
62 | _ ->
63 | []
64 | end,
65 | case filelib:is_file(DumpFile) of
66 | true ->
67 | [{warning, {crash_dump, DumpFile}}|Messages];
68 | _ ->
69 | Messages
70 | end.
71 |
72 | -spec format(term()) -> {io:format(), [term()]}.
73 | format({eacces, Dir}) ->
74 | {"Crash dump directory ~s is not writeable by Riak. Please set -env ERL_CRASH_DUMP /erl_crash.dump in vm.args to a writeable path.", [Dir]};
75 | format({enoent, Dir}) ->
76 | {"Crash dump directory ~s does not exist. Please set -env ERL_CRASH_DUMP /erl_crash.dump in vm.args to a writeable path.", [Dir]};
77 | format({crash_dump, File}) ->
78 | {ok, #file_info{mtime=MTime}} = file:read_file_info(File),
79 | {"Riak crashed at ~s, leaving crash dump in ~s. Please inspect or remove the file.", [httpd_util:rfc1123_date(MTime), File]}.
80 |
--------------------------------------------------------------------------------
/src/riaknostic_check_memory_use.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks Riak's current memory usage. If memory
24 | %% usage is high, a warning message will be sent, otherwise only
25 | %% informational messages.
26 | -module(riaknostic_check_memory_use).
27 | -behaviour(riaknostic_check).
28 |
29 | -export([description/0,
30 | valid/0,
31 | check/0,
32 | format/1]).
33 |
34 | -spec description() -> string().
35 | description() ->
36 | "Measure memory usage".
37 |
38 | -spec valid() -> boolean().
39 | valid() ->
40 | riaknostic_node:can_connect().
41 |
42 | -spec check() -> [{lager:log_level(), term()}].
43 | check() ->
44 | Pid = riaknostic_node:pid(),
45 | Output = riaknostic_util:run_command("ps -o pmem,rss -p " ++ Pid),
46 | [_,_,Percent, RealSize| _] = string:tokens(Output, "/n \n"),
47 | Messages = [
48 | {info, {process_usage, Percent, RealSize}}
49 | ],
50 | case riaknostic_util:binary_to_float(list_to_binary(Percent)) >= 90 of
51 | false ->
52 | Messages;
53 | true ->
54 | [{critical, {high_memory, Percent}} | Messages]
55 | end.
56 |
57 | -spec format(term()) -> {io:format(), [term()]}.
58 | format({high_memory, Percent}) ->
59 | {"Riak memory usage is HIGH: ~s% of available RAM", [Percent]};
60 | format({process_usage, Percent, Real}) ->
61 | {"Riak process is using ~s% of available RAM, totalling ~s KB of real memory.", [Percent, Real]}.
62 |
--------------------------------------------------------------------------------
/src/riaknostic_check_monitors.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that notes processes which have a high monitor count(>50)
24 | -module(riaknostic_check_monitors).
25 | -behaviour(riaknostic_check).
26 |
27 | -export([description/0,
28 | valid/0,
29 | check/0,
30 | format/1]).
31 |
32 | -spec description() -> string().
33 | description() ->
34 | "Note processes with >50 monitors".
35 |
36 | -spec valid() -> boolean().
37 | valid() ->
38 | riaknostic_node:can_connect().
39 |
40 | -spec check() -> [{lager:log_level(), term()}].
41 | check() ->
42 | Fun = fun() -> [{Pid,NumMon} || Pid <- processes(),
43 | [{monitors,Mon}] <- [process_info(Pid, [monitors])],
44 | NumMon <- [length(Mon)],
45 | NumMon > 50] end,
46 | case riaknostic_node:local_command(erlang, apply, [Fun,[]]) of
47 | [] ->
48 | [];
49 | Pids ->
50 | [{warning, {high_monitor_count, Pids}}]
51 | end.
52 |
53 | -spec format(term()) -> {io:format(), [term()]}.
54 | format({high_monitor_count, Pids}) ->
55 | {"The following processes have more than 50 monitors: ~p", [Pids]}.
--------------------------------------------------------------------------------
/src/riaknostic_check_nodes_connected.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic check that detects cluster members that are down.
24 | -module(riaknostic_check_nodes_connected).
25 | -behaviour(riaknostic_check).
26 |
27 | -export([description/0,
28 | valid/0,
29 | check/0,
30 | format/1]).
31 |
32 | -spec description() -> string().
33 | description() ->
34 | "Cluster node liveness".
35 |
36 | -spec valid() -> boolean().
37 | valid() ->
38 | riaknostic_node:can_connect().
39 |
40 | -spec check() -> [{lager:log_level(), term()}].
41 | check() ->
42 | Stats = riaknostic_node:stats(),
43 | {connected_nodes, ConnectedNodes} = lists:keyfind(connected_nodes, 1, Stats),
44 | {ring_members, RingMembers} = lists:keyfind(ring_members, 1, Stats),
45 | {nodename, NodeName} = lists:keyfind(nodename, 1, Stats),
46 |
47 | [ {warning, {node_disconnected, N}} || N <- RingMembers,
48 | N =/= NodeName,
49 | lists:member(N, ConnectedNodes) == false].
50 |
51 | -spec format(term()) -> {io:format(), [term()]}.
52 | format({node_disconnected, Node}) ->
53 | {"Cluster member ~s is not connected to this node. Please check whether it is down.", [Node]}.
54 |
--------------------------------------------------------------------------------
/src/riaknostic_check_ring_membership.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks whether the local node is a member of
24 | %% the ring. This might arise when the node name in vm.args has
25 | %% changed but the node has not been renamed in the ring.
26 | -module(riaknostic_check_ring_membership).
27 | -behaviour(riaknostic_check).
28 |
29 | -export([description/0,
30 | valid/0,
31 | check/0,
32 | format/1]).
33 |
34 | -include_lib("eunit/include/eunit.hrl").
35 |
36 | -spec description() -> string().
37 | description() ->
38 | "Cluster membership validity".
39 |
40 | -spec valid() -> boolean().
41 | valid() ->
42 | riaknostic_node:can_connect().
43 |
44 | -spec check() -> [{lager:log_level(), term()}].
45 | check() ->
46 | Stats = riaknostic_node:stats(),
47 | {ring_members, RingMembers} = lists:keyfind(ring_members, 1, Stats),
48 | {nodename, NodeName} = lists:keyfind(nodename, 1, Stats),
49 | case lists:member(NodeName, RingMembers) of
50 | true ->
51 | [];
52 | false ->
53 | [{warning, {not_ring_member, NodeName}}]
54 | end.
55 |
56 | check_test() ->
57 | meck:new(riaknostic_node, [passthrough]),
58 | meck:expect(riaknostic_node, stats, fun() -> [{ring_members, ["riak@127.0.0.1"]}, {nodename, ["notmember@127.0.0.1"]}] end),
59 | ?assert(meck:validate(riaknostic_node)),
60 | ?assertEqual([{warning, {not_ring_member, ["notmember@127.0.0.1"]}}], check()),
61 | ?assertNotEqual([{warning, {not_ring_member, ["notequal@127.0.0.1"]}}], check()),
62 | meck:unload(riaknostic_node).
63 |
64 | -spec format(term()) -> {io:format(), [term()]}.
65 | format({not_ring_member, Nodename}) ->
66 | {"Local node ~w is not a member of the ring. Please check that the -name setting in vm.args is correct.", [Nodename]}.
67 |
--------------------------------------------------------------------------------
/src/riaknostic_check_ring_preflists.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks the local ring for any preflists that do
24 | %% not satisfy n_val
25 | -module(riaknostic_check_ring_preflists).
26 | -behaviour(riaknostic_check).
27 |
28 | -export([description/0,
29 | valid/0,
30 | check/0,
31 | format/1]).
32 |
33 | -spec description() -> string().
34 | description() ->
35 | "Check ring satisfies n_val".
36 |
37 | -spec valid() -> boolean().
38 | valid() ->
39 | riaknostic_node:can_connect().
40 |
41 | -spec check() -> [{lager:log_level(), term()}].
42 | check() ->
43 | case riaknostic_node:local_command(riak_core_ring_util, check_ring) of
44 | [] -> [];
45 | PrefLists -> [ {warning, {n_val_not_satisfied, PrefLists}} ]
46 | end.
47 |
48 | -spec format(term()) -> {io:format(), [term()]}.
49 | format({n_val_not_satisfied, PrefLists}) ->
50 | {"The following preflists do not satisfy the n_val. Please add more nodes. ~p", [PrefLists]}.
51 |
52 |
--------------------------------------------------------------------------------
/src/riaknostic_check_ring_size.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that compares the configured
24 | %% ring_creation_size to the actual size of the ring.
25 | -module(riaknostic_check_ring_size).
26 | -behaviour(riaknostic_check).
27 |
28 | -export([description/0,
29 | valid/0,
30 | check/0,
31 | format/1]).
32 |
33 | -spec description() -> string().
34 | description() ->
35 | "Ring size valid".
36 |
37 | -spec valid() -> boolean().
38 | valid() ->
39 | riaknostic_node:can_connect().
40 |
41 | -spec check() -> [{lager:log_level(), term()}].
42 | check() ->
43 | Stats = riaknostic_node:stats(),
44 | {ring_creation_size, RingSize} = lists:keyfind(ring_creation_size, 1, Stats),
45 | {ring_num_partitions, NumPartitions} = lists:keyfind(ring_num_partitions, 1, Stats),
46 | % {ring_members, RingMembers} = lists:keyfind(ring_members, 1, Stats),
47 | % NumRingMembers = length(RingMembers),
48 | % VnodesPerNode = erlang:round(RingSize / NumRingMembers),
49 | % MinAcceptableVnodesPerNode = erlang:round(RingSize * 0.03),
50 | % MaxRecommendedVnodesPerNode = erlang:round(RingSize * 0.7),
51 |
52 | lists:append([
53 | [ {notice, {ring_size_unequal, RingSize, NumPartitions}} || RingSize /= NumPartitions ],
54 | [ {critical, {ring_size_not_exp2, RingSize}} || (RingSize band -(bnot RingSize)) /= RingSize]
55 | % [ {notice, {ring_size_too_small, RingSize, NumRingMembers}} || VnodesPerNode =< MinAcceptableVnodesPerNode ],
56 | % [ {notice, {too_few_nodes_for_ring, RingSize, NumRingMembers}} || VnodesPerNode >= MaxRecommendedVnodesPerNode ]
57 | ]).
58 |
59 | -spec format(term()) -> {io:format(), [term()]}.
60 | format({ring_size_unequal, S, P}) ->
61 | {"The configured ring_creation_size (~B) is not equal to the number of partitions in the ring (~B). "
62 | "Please verify that the ring_creation_size in app.config is correct.", [S, P]};
63 |
64 | format({ring_size_not_exp2, S}) ->
65 | {"The configured ring_creation_size (~B) should always be a power of 2. "
66 | "Please reconfigure the ring_creation_size in app.config.", [S]}.
67 |
68 | %format({ring_size_too_small, S, N}) ->
69 | % {"With a ring_creation_size (~B) and ~B nodes participating in the cluster, each node is responsible for less than 3% of the data. "
70 | % " You have too many nodes for this size ring. "
71 | % "Please consider migrating data to a cluster with 2 or 4x your current ring size.", [S, N]};
72 |
73 | %format({too_few_nodes_for_ring, S, N}) ->
74 | % {"With a ring_creation_size (~B) and ~B nodes participating in the cluster, each node is responsible for more than 70% of the data. "
75 | % " You have too few nodes for this size ring. "
76 | % "Please consider joining more nodes to your cluster.", [S, N]}.
77 |
--------------------------------------------------------------------------------
/src/riaknostic_check_search.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks if riak_search
24 | %% is enabled on every node
25 | -module(riaknostic_check_search).
26 | -behaviour(riaknostic_check).
27 |
28 | -export([description/0,
29 | valid/0,
30 | check/0,
31 | format/1]).
32 |
33 | -spec description() -> string().
34 | description() ->
35 | "Check whether search is enabled on all nodes".
36 |
37 | -spec valid() -> boolean().
38 | valid() ->
39 | riaknostic_node:can_connect_all().
40 |
41 | -spec check() -> [{lager:log_level(), term()}].
42 | check() ->
43 | Stats = riaknostic_node:stats(),
44 | {ring_members, RingMembers} = lists:keyfind(ring_members, 1, Stats),
45 |
46 | {SearchEnabled, _} = riaknostic_node:cluster_command(application, get_env, [riak_search, enabled]),
47 |
48 | {_, X} = lists:unzip(SearchEnabled),
49 | NodesSearchEnabled = lists:zip(RingMembers, X),
50 |
51 | lists:append([
52 | [ {warning, {riak_search, NodesSearchEnabled}} || length(lists:usort(SearchEnabled)) > 1 ]
53 | ]).
54 |
55 | -spec format(term()) -> {io:format(), [term()]}.
56 | format({riak_search, Services}) ->
57 | {"Search is not enabled on all nodes: ~p", [Services]}.
58 |
--------------------------------------------------------------------------------
/src/riaknostic_check_strong_consistency.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Diagnostic that checks Riak's current memory usage. If memory
24 | %% usage is high, a warning message will be sent, otherwise only
25 | %% informational messages.
26 | -module(riaknostic_check_strong_consistency).
27 | -behaviour(riaknostic_check).
28 |
29 | -export([description/0,
30 | valid/0,
31 | check/0,
32 | format/1]).
33 |
34 | -spec description() -> string().
35 | description() ->
36 | "Strong consistency configuration valid".
37 |
38 | -spec valid() -> boolean().
39 | valid() ->
40 | riaknostic_node:can_connect().
41 |
42 | -spec check() -> [{lager:log_level(), term()}].
43 | check() ->
44 | StrongConsistencyOption = riaknostic_config:get_app_env([riak_core, enable_consensus]),
45 | { AAEOption, _ } = riaknostic_config:get_app_env([riak_kv, anti_entropy]),
46 | maybe_strong_consistency_aae_misconfigured(StrongConsistencyOption, AAEOption).
47 |
48 | -spec maybe_strong_consistency_aae_misconfigured(boolean, on | off | any()) -> [ { term(), term() } ] | [].
49 | maybe_strong_consistency_aae_misconfigured(true, off) ->
50 | [ { critical, { strong_consistency_aae_misconfigured } } ];
51 | maybe_strong_consistency_aae_misconfigured(false, _) ->
52 | [];
53 | maybe_strong_consistency_aae_misconfigured(true, on) ->
54 | [].
55 |
56 | -spec format(term()) -> {io:format(), [term()]}.
57 | format({ strong_consistency_aae_misconfigured }) ->
58 | { "Strong consistency has been enabled without AAE -- all consistent operations will timeout until AAE is enabled.", [] }.
59 |
--------------------------------------------------------------------------------
/src/riaknostic_config.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Provides convenient access to Riak configuration values. When
24 | %% the {@link riaknostic. riaknostic} module calls {@link
25 | %% prepare/0. prepare/0}, Riak's app.config and
26 | %% vm.args files will be parsed and memoized, and lager
27 | %% will be started on the console at the configured severity level.
28 | %% @end
29 |
30 | -module(riaknostic_config).
31 |
32 | -export([prepare/0,
33 | data_directories/0,
34 | get_app_env/1,
35 | get_app_env/2,
36 | get_vm_env/1,
37 | base_dir/0,
38 | etc_dir/0,
39 | node_name/0,
40 | cookie/0,
41 | user/0]).
42 |
43 | %% @doc Prepares appropriate configuration so the riaknostic script
44 | %% can run. This is called by the riaknostic module and you do
45 | %% not need to invoke it.
46 | -spec prepare() -> ok | {error, iodata()}.
47 | prepare() ->
48 | prepare([fun start_lager/0, fun load_app_config/0, fun load_vm_args/0]).
49 |
50 | prepare([]) ->
51 | ok;
52 | prepare([Fun|T]) ->
53 | case Fun() of
54 | {error, Reason} ->
55 | {error, Reason};
56 | _ ->
57 | prepare(T)
58 | end.
59 |
60 | %% @doc Determines where Riak is configured to store data. Returns a
61 | %% list of paths to directories defined by storage backends.
62 | -spec data_directories() -> [ file:filename() ].
63 | data_directories() ->
64 | KVBackend = get_app_env([riak_kv, storage_backend]),
65 | SearchBackend = get_app_env([riak_search, storage_backend], merge_index_backend),
66 | Dirs = case get_app_env([riak_search, enabled]) of
67 | true ->
68 | data_directory(KVBackend) ++ data_directory(SearchBackend);
69 | _ ->
70 | data_directory(KVBackend)
71 | end,
72 | [ filename:absname(Dir, base_dir()) || Dir <- Dirs, Dir =/= undefined ].
73 |
74 | %% @doc Get a key out of the app.config file, or if it doesn't exist,
75 | %% return the Default. You specify a nested key using a list of atoms,
76 | %% e.g. [riak_kv, storage_backend].
77 | %% @see get_app_env/1
78 | -spec get_app_env([atom()], term()) -> term().
79 | get_app_env(Keys, Default) ->
80 | case get_app_env(Keys) of
81 | undefined ->
82 | Default;
83 | Value ->
84 | Value
85 | end.
86 |
87 | %% @doc Get a key out of the app.config file. You specify a nested
88 | %% key using a list of atoms, e.g. [riak_kv, storage_backend].
89 | %% @equiv get_app_env(Keys, undefined)
90 | -spec get_app_env([atom()]) -> undefined | term().
91 | get_app_env(Keys) ->
92 | {ok, Env} = application:get_env(riaknostic, app_config),
93 | find_nested_key(Keys, Env).
94 |
95 | %% @doc Get an -env flag out of the vm.args file.
96 | -spec get_vm_env(string()) -> string() | undefined.
97 | get_vm_env(Key) ->
98 | case application:get_env(riaknostic, vm_env) of
99 | undefined ->
100 | undefined;
101 | {ok, PList} ->
102 | proplists:get_value(Key, PList)
103 | end.
104 |
105 | %% @doc Determines the user/uid that the installed Riak runs as.
106 | -spec user() -> string().
107 | user() ->
108 | case application:get_env(riaknostic, user) of
109 | {ok, Value} ->
110 | Value;
111 | _ -> undefined
112 | end.
113 |
114 | %% @doc The base directory from which the Riak script runs.
115 | -spec base_dir() -> file:filename().
116 | base_dir() ->
117 | case application:get_env(riaknostic, base) of
118 | undefined ->
119 | filename:absname(".");
120 | {ok, Path} ->
121 | filename:absname(Path)
122 | end.
123 |
124 | %% @doc The Riak configuration directory.
125 | -spec etc_dir() -> file:filename().
126 | etc_dir() ->
127 | case application:get_env(riaknostic, etc) of
128 | undefined ->
129 | filename:absname("./etc", base_dir());
130 | {ok, Path} ->
131 | filename:absname(Path, base_dir())
132 | end.
133 |
134 | %% @doc The local Riak node name. Includes whether the node uses short
135 | %% or long nodenames for distributed Erlang.
136 | -spec node_name() -> {shortnames | longnames, Name::string()}.
137 | node_name() ->
138 | case application:get_env(riaknostic, node_name) of
139 | undefined ->
140 | undefined;
141 | {ok, Node} ->
142 | Node
143 | end.
144 |
145 | %% @doc The Riak node's distributed Erlang cookie.
146 | -spec cookie() -> atom().
147 | cookie() ->
148 | case application:get_env(riaknostic, cookie) of
149 | undefined ->
150 | undefined;
151 | {ok, Cookie} ->
152 | list_to_atom(Cookie)
153 | end.
154 |
155 | %% Private functions
156 | start_lager() ->
157 | application:load(lager),
158 | case application:get_env(riaknostic, log_level) of
159 | undefined ->
160 | {error, "Log level not set!"};
161 | {ok, Level} ->
162 | application:set_env(lager, crash_log, undefined),
163 | application:set_env(lager, handlers, [{lager_console_backend, Level}]),
164 | lager:start()
165 | end.
166 |
167 | load_app_config() ->
168 | {ok, [[AppConfig]]} = init:get_argument(config),
169 | case file:consult(AppConfig) of
170 | {ok, [Config]} ->
171 | application:set_env(riaknostic, app_config, Config);
172 | _ ->
173 | {error, io_lib:format("Riak config file ~s is malformed!", [AppConfig])}
174 | end.
175 |
176 | load_vm_args() ->
177 | VmArgs = case init:get_argument(vm_args) of
178 | {ok, [[X]]} -> X;
179 | _ ->
180 | %% This is a backup. If for some reason -vm_args isn't specified
181 | %% then assume it lives in the same dir as app.config
182 | {ok, [[AppConfig]]} = init:get_argument(config),
183 | AppIndex = string:str(AppConfig, "app"),
184 | ConfigIndex = string:rstr(AppConfig, "config"),
185 | string:sub_string(AppConfig, 1, AppIndex - 1) ++ "vm" ++
186 | string:sub_string(AppConfig, AppIndex + 3, ConfigIndex-1) ++ "args"
187 | end,
188 |
189 | case file:read_file(VmArgs) of
190 | {error, Reason} ->
191 | {error, io_lib:format("Could not read ~s, received error ~w!", [VmArgs, Reason])};
192 | {ok, Binary} ->
193 | load_vm_args(Binary)
194 | end.
195 |
196 | load_vm_args(Bin) when is_binary(Bin) ->
197 | load_vm_args(re:split(Bin, "\s*\r?\n\s*", [{return, list}, trim]));
198 | load_vm_args([]) ->
199 | ok;
200 | load_vm_args([[$#|_]|T]) ->
201 | load_vm_args(T);
202 | load_vm_args([""|T]) ->
203 | load_vm_args(T);
204 | load_vm_args(["-sname " ++ NodeName|T]) ->
205 | application:set_env(riaknostic, node_name, {shortnames, string:strip(NodeName)}),
206 | load_vm_args(T);
207 | load_vm_args(["-name " ++ NodeName|T]) ->
208 | application:set_env(riaknostic, node_name, {longnames, string:strip(NodeName)}),
209 | load_vm_args(T);
210 | load_vm_args(["-setcookie " ++ Cookie|T]) ->
211 | application:set_env(riaknostic, cookie, string:strip(Cookie)),
212 | load_vm_args(T);
213 | load_vm_args(["-env " ++ Env|T]) ->
214 | [Key, Value] = re:split(Env, "\s+", [{return, list}, trim]),
215 | add_or_insert_env(vm_env, {Key, Value}),
216 | load_vm_args(T);
217 | load_vm_args([[$+|EmuFlags]|T]) ->
218 | [Flag|Rest] = re:split(EmuFlags, "\s+", [{return,list}, trim]),
219 | add_or_insert_env(emu_flags, {[$+|Flag], Rest}),
220 | load_vm_args(T);
221 | load_vm_args([[$-|InitFlags]|T]) ->
222 | [Flag|Rest] = re:split(InitFlags, "\s+", [{return,list}, trim]),
223 | add_or_insert_env(init_flags, {[$-|Flag], Rest}),
224 | load_vm_args(T);
225 | load_vm_args([Line|_]) ->
226 | {error, io_lib:format("Erroneous line in vm.args: ~s", [Line])}.
227 |
228 | add_or_insert_env(Key, Value) ->
229 | case application:get_env(riaknostic, Key) of
230 | undefined ->
231 | application:set_env(riaknostic, Key, [Value]);
232 | {ok, List} ->
233 | application:set_env(riaknostic, Key, [Value|List])
234 | end.
235 |
236 | find_nested_key(_, undefined) ->
237 | undefined;
238 | find_nested_key([], Val) ->
239 | Val;
240 | find_nested_key([Key|T], PList) ->
241 | find_nested_key(T, proplists:get_value(Key, PList)).
242 |
243 | %% Determine the data directory(ies) for the configured storage backend
244 | -spec data_directory(atom()) -> [ file:filename() ].
245 | data_directory(riak_kv_bitcask_backend) ->
246 | [ get_app_env([bitcask, data_root]) ];
247 | data_directory(riak_kv_eleveldb_backend) ->
248 | [ get_app_env([eleveldb, data_root]) ];
249 | data_directory(merge_index_backend) ->
250 | [ get_app_env([merge_index, data_root]) ];
251 | data_directory(riak_kv_innostore_backend) ->
252 | [ get_app_env([innostore, data_home_dir]),
253 | get_app_env([innostore, log_group_home_dir]) ];
254 | data_directory(riak_kv_multi_backend) ->
255 | [ multi_data_directory(Backend) ||
256 | Backend <- get_app_env([riak_kv, multi_backend]),
257 | element(2, Backend) =/= riak_kv_memory_backend ];
258 | data_directory(_) -> %% Memory or unknown backend
259 | [].
260 |
261 | %% Extracts data paths from multi_backend config
262 | multi_data_directory({_, riak_kv_bitcask_backend, Props}) ->
263 | case proplists:get_value(data_root, Props) of
264 | undefined ->
265 | get_app_env([bitcask, data_root]);
266 | Path when is_list(Path) ->
267 | Path
268 | end;
269 | multi_data_directory({_, riak_kv_eleveldb_backend, Props}) ->
270 | case proplists:get_value(data_root, Props) of
271 | undefined ->
272 | get_app_env([eleveldb, data_root]);
273 | Path when is_list(Path) ->
274 | Path
275 | end;
276 | multi_data_directory({_, riak_kv_innostore_backend, Props}) ->
277 | case proplists:get_value(data_home_dir, Props) of
278 | undefined ->
279 | get_app_env([innostore, data_home_dir]);
280 | Path when is_list(Path) ->
281 | Path
282 | end.
283 |
--------------------------------------------------------------------------------
/src/riaknostic_node.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Functions that help diagnostics interact with the local Riak
24 | %% node or other members of the cluster.
25 | -module(riaknostic_node).
26 |
27 | -export([can_connect/0,
28 | can_connect_all/0,
29 | stats/0,
30 | pid/0,
31 | local_command/2,
32 | local_command/3,
33 | local_command/4,
34 | cluster_command/2,
35 | cluster_command/3,
36 | cluster_command/4
37 | ]).
38 |
39 | %% @doc Calls the given 0-arity module and function on the local Riak
40 | %% node and returns the result of that call.
41 | %% @equiv local_command(Module, Function, [])
42 | %% @see can_connect/0.
43 | -spec local_command(Module::atom(), Function::atom()) -> term().
44 | local_command(Module, Function) ->
45 | local_command(Module, Function, []).
46 |
47 | %% @doc Calls the given module and function with the given arguments
48 | %% on the local Riak node and returns the result of that call.
49 | %% @equiv local_command(Module, Function, Args, 5000)
50 | %% @see can_connect/0
51 | -spec local_command(Module::atom(), Function::atom(), Args::[term()]) -> term().
52 | local_command(Module, Function, Args) ->
53 | local_command(Module, Function, Args, 5000).
54 |
55 | %% @doc Calls the given module and function with the given arguments
56 | %% on the local Riak node and returns the result of that call,
57 | %% returning an error if the call doesn't complete within the given
58 | %% timeout.
59 | %% @equiv rpc:call(RiakNodeName, Module, Function, Args, Timeout)
60 | %% @see can_connect/0
61 | -spec local_command(Module::atom(), Function::atom(), Args::[term()], Timeout::integer()) -> term().
62 | local_command(Module, Function, Args, Timeout) ->
63 | riaknostic_util:log(debug, "Local RPC: ~p:~p(~p) [~p]", [Module, Function, Args, Timeout]),
64 | rpc:call(nodename(), Module, Function, Args, Timeout).
65 |
66 | %% @doc Calls the given 0-arity module and function on all members of
67 | %% the Riak cluster.
68 | %% @equiv cluster_command(Module, Function, [])
69 | %% @see can_connect/0
70 | -spec cluster_command(Module::atom(), Function::atom()) -> term().
71 | cluster_command(Module, Function) ->
72 | cluster_command(Module, Function, []).
73 |
74 | %% @doc Calls the given module and function with the given arguments
75 | %% on all members of the Riak cluster.
76 | %% @equiv cluster_command(Module, Function, Args, 5000)
77 | %% @see can_connect/0
78 | -spec cluster_command(Module::atom(), Function::atom(), Args::[term()]) -> term().
79 | cluster_command(Module, Function, Args) ->
80 | cluster_command(Module, Function, Args, 5000).
81 |
82 | %% @doc Calls the given module and function with the given arguments
83 | %% on all members for the Riak cluster, returning an error if the call
84 | %% doesn't complete within the given timeout.
85 | %% @equiv rpc:multicall(RiakClusterMembers, Module, Function, Args, Timeout)
86 | %% @see can_connect/0
87 | -spec cluster_command(Module::atom(), Function::atom(), Args::[term()], Timeout::integer()) -> term().
88 | cluster_command(Module, Function, Args, Timeout) ->
89 | riaknostic_util:log(debug, "Cluster RPC: ~p:~p(~p) [~p]", [Module, Function, Args, Timeout]),
90 | Stats = stats(),
91 | {ring_members, RingMembers} = lists:keyfind(ring_members, 1, Stats),
92 | rpc:multicall(RingMembers, Module, Function, Args, Timeout).
93 |
94 | %% @doc Retrieves the operating system's process ID of the local Riak
95 | %% node.
96 | %% @equiv local_command(os, getpid)
97 | %% @see can_connect/0
98 | -spec pid() -> string().
99 | pid() ->
100 | local_command(os, getpid).
101 |
102 | %% @doc Attempts to connect to the local Riak node if it is not
103 | %% already, and returns whether connection was successful.
104 | -spec can_connect() -> true | false.
105 | can_connect() ->
106 | case is_connected() of
107 | true -> true;
108 | false ->
109 | riaknostic_util:log(debug, "Not connected to the local Riak node, trying to connect. alive:~p connect_failed:~p", [is_alive(), connect_failed()]),
110 | maybe_connect()
111 | end.
112 |
113 | -spec can_connect_all() -> true | false.
114 | can_connect_all() ->
115 | case is_connected() of
116 | true ->
117 | case riaknostic_check_nodes_connected:check() of
118 | [] -> true;
119 | _ -> false
120 | end;
121 | false -> false
122 | end.
123 |
124 | %% @doc Fetches or returns previously fetched Riak statistics.
125 | %% @see can_connect/0
126 | -spec stats() -> [proplists:property()].
127 | stats() ->
128 | case has_stats() of
129 | {ok, Stats} -> Stats;
130 | _ -> fetch_stats()
131 | end.
132 |
133 | %% Private functions
134 | is_connected() ->
135 | is_alive() andalso connect_failed() =/= true.
136 |
137 | maybe_connect() ->
138 | case connect_failed() of
139 | true -> false;
140 | _ -> try_connect()
141 | end.
142 |
143 | try_connect() ->
144 | TargetNode = nodename(),
145 | case is_alive() of
146 | true -> ok;
147 | _ -> start_net()
148 | end,
149 | case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
150 | {true, pong} ->
151 | application:set_env(riaknostic, connect_failed, false),
152 | riaknostic_util:log(debug, "Connected to local Riak node ~p.", [TargetNode]),
153 | true;
154 | _ ->
155 | application:set_env(riaknostic, connect_failed, true),
156 | lager:warning("Could not connect to the local Riak node ~p, some checks will not run.", [TargetNode]),
157 | false
158 | end.
159 |
160 | connect_failed() ->
161 | case application:get_env(riaknostic, connect_failed) of
162 | {ok, true} -> true;
163 | undefined -> undefined;
164 | _ -> false
165 | end.
166 |
167 | start_net() ->
168 | riaknostic_util:log(debug, "Starting distributed Erlang."),
169 | {Type, RiakName} = riaknostic_config:node_name(),
170 | ThisNode = append_node_suffix(RiakName, "_diag"),
171 | {ok, _} = net_kernel:start([ThisNode, Type]),
172 | erlang:set_cookie(node(), riaknostic_config:cookie()).
173 |
174 | nodename() ->
175 | {_, Name} = riaknostic_config:node_name(),
176 | case string:tokens(Name, "@") of
177 | [_Node, _Host] ->
178 | list_to_atom(Name);
179 | [Node] ->
180 | [_, Host] = string:tokens(atom_to_list(node()), "@"),
181 | list_to_atom(lists:concat([Node, "@", Host]))
182 | end.
183 |
184 | append_node_suffix(Name, Suffix) ->
185 | case string:tokens(Name, "@") of
186 | [Node, Host] ->
187 | list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host]));
188 | [Node] ->
189 | list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
190 | end.
191 |
192 | has_stats() ->
193 | case application:get_env(riaknostic, local_stats) of
194 | {ok, {badrpc, _Reason}} ->
195 | false;
196 | {ok, Stats} ->
197 | {ok, Stats};
198 | undefined ->
199 | false
200 | end.
201 |
202 | fetch_stats() ->
203 | riaknostic_util:log(debug, "Fetching local riak_kv_status."),
204 | case local_command(riak_kv_status, statistics) of
205 | [] -> [];
206 | PList ->
207 | application:set_env(riaknostic, local_stats, PList),
208 | PList
209 | end.
210 |
211 |
--------------------------------------------------------------------------------
/src/riaknostic_util.erl:
--------------------------------------------------------------------------------
1 | %% -------------------------------------------------------------------
2 | %%
3 | %% riaknostic - automated diagnostic tools for Riak
4 | %%
5 | %% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
6 | %%
7 | %% This file is provided to you under the Apache License,
8 | %% Version 2.0 (the "License"); you may not use this file
9 | %% except in compliance with the License. You may obtain
10 | %% a copy of the License at
11 | %%
12 | %% http://www.apache.org/licenses/LICENSE-2.0
13 | %%
14 | %% Unless required by applicable law or agreed to in writing,
15 | %% software distributed under the License is distributed on an
16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 | %% KIND, either express or implied. See the License for the
18 | %% specific language governing permissions and limitations
19 | %% under the License.
20 | %%
21 | %% -------------------------------------------------------------------
22 |
23 | %% @doc Utility functions for riaknostic.
24 | %% @end
25 | -module(riaknostic_util).
26 | -export([short_name/1,
27 | run_command/1,
28 | log/2,log/3,
29 | binary_to_float/1]).
30 |
31 | %% @doc Converts a check module name into a short name that can be
32 | %% used to refer to a check on the command line. For example,
33 | %% riaknostic_check_disk becomes"disk".
34 | -spec short_name(module()) -> iodata() | unicode:charlist().
35 | short_name(Mod) when is_atom(Mod) ->
36 | re:replace(atom_to_list(Mod), "riaknostic_check_", "", [{return, list}]).
37 |
38 | %% @doc Runs a shell command and returns the output. stderr is
39 | %% redirected to stdout so its output will be included.
40 | -spec run_command(Command::iodata()) -> StdOut::iodata().
41 | run_command(Command) ->
42 | riaknostic_util:log(debug, "Running shell command: ~s", [Command]),
43 | Port = erlang:open_port({spawn,Command},[exit_status, stderr_to_stdout]),
44 | do_read(Port, []).
45 |
46 | do_read(Port, Acc) ->
47 | receive
48 | {Port, {data, StdOut}} ->
49 | riaknostic_util:log(debug, "Shell command output: ~n~s~n",[StdOut]),
50 | do_read(Port, Acc ++ StdOut);
51 | {Port, {exit_status, _}} ->
52 | %%port_close(Port),
53 | Acc;
54 | Other ->
55 | io:format("~w", [Other]),
56 | do_read(Port, Acc)
57 | end.
58 |
59 | %% @doc Converts a binary containing a text representation of a float
60 | %% into a float type.
61 | -spec binary_to_float(binary()) -> float().
62 | binary_to_float(Bin) ->
63 | list_to_float(binary_to_list(Bin)).
64 |
65 | log(Level, Format, Terms) ->
66 | case should_log(Level) of
67 | true ->
68 | io:format(lists:concat(["[", Level, "] ", Format, "~n"]), Terms);
69 | false ->
70 | ok
71 | end,
72 | lager:log(Level, self(), Format, Terms).
73 |
74 | log(Level, String) ->
75 | case should_log(Level) of
76 | true ->
77 | io:format(lists:concat(["[", Level, "] ", String, "~n"]));
78 | false ->
79 | ok
80 | end,
81 | lager:log(Level, self(), String).
82 |
83 | should_log(Level) ->
84 | AppLevel = case application:get_env(riaknostic, log_level) of
85 | undefined -> info;
86 | {ok, L0} -> L0
87 | end,
88 | lager_util:level_to_num(AppLevel) >= lager_util:level_to_num(Level).
89 |
90 |
--------------------------------------------------------------------------------