Compare commits
656 Commits
v3.0-beta3
...
v3.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bfccd77d4 | ||
|
|
a4d27083d0 | ||
|
|
a9cf7cd4f0 | ||
|
|
44d1393480 | ||
|
|
b46af0069e | ||
|
|
741b7353c1 | ||
|
|
c4e7a3ae89 | ||
|
|
89dc3b88d1 | ||
|
|
971e2d62f1 | ||
|
|
66a72e9ece | ||
|
|
0de0f4d014 | ||
|
|
9f777a535b | ||
|
|
ddf579f204 | ||
|
|
3abbf08a17 | ||
|
|
474a821767 | ||
|
|
3ae327320a | ||
|
|
78d0badffe | ||
|
|
575b015fe0 | ||
|
|
b9a2546a10 | ||
|
|
6c2a61001a | ||
|
|
d007363e7c | ||
|
|
b2acac3a41 | ||
|
|
f3db2fa262 | ||
|
|
5b4fd8e9c8 | ||
|
|
81af8f072c | ||
|
|
eb35f8cb89 | ||
|
|
65683ab241 | ||
|
|
4c4cb20bde | ||
|
|
4133526d8d | ||
|
|
12d455f3c3 | ||
|
|
615b692442 | ||
|
|
ebdf0564eb | ||
|
|
68a8d9bc91 | ||
|
|
85be7dd902 | ||
|
|
d44325affd | ||
|
|
5a8efa9a52 | ||
|
|
b62f1f00cd | ||
|
|
4545b4d323 | ||
|
|
d74eb8c188 | ||
|
|
b275fa8109 | ||
|
|
60f45c965c | ||
|
|
efad4bcb56 | ||
|
|
9435e70b37 | ||
|
|
2063fee4fe | ||
|
|
c3e1955792 | ||
|
|
838284c09f | ||
|
|
1d35b90484 | ||
|
|
f3c1a894de | ||
|
|
af1c8dc5d9 | ||
|
|
2123fbdf9b | ||
|
|
14169c5092 | ||
|
|
0555525f97 | ||
|
|
24a54cd95b | ||
|
|
a7a5f36b49 | ||
|
|
ab0155c861 | ||
|
|
53c424caf8 | ||
|
|
23cfbac4ec | ||
|
|
f23d72001d | ||
|
|
302ad5f1f9 | ||
|
|
257e6c469e | ||
|
|
ef9766eb96 | ||
|
|
aa9e524e73 | ||
|
|
3b1ae3f7d2 | ||
|
|
cccfe47bf0 | ||
|
|
87ab97b5ed | ||
|
|
3b47b1ecbd | ||
|
|
12706fd6db | ||
|
|
d8be2f1ecc | ||
|
|
b6f9d9feb0 | ||
|
|
8efa94e42a | ||
|
|
b94527f661 | ||
|
|
3adee1eda0 | ||
|
|
398e9f5195 | ||
|
|
90c063060a | ||
|
|
3bcda9268a | ||
|
|
e2b398a6bf | ||
|
|
fa10fc994a | ||
|
|
cb2b8dea96 | ||
|
|
9bcd5de8ff | ||
|
|
9f9fca1e76 | ||
|
|
fdf46c6a10 | ||
|
|
305a6ae110 | ||
|
|
10daf1d63a | ||
|
|
23aa614baf | ||
|
|
5c35fac8fe | ||
|
|
8b2f6fffc9 | ||
|
|
32479503bd | ||
|
|
b06ec734f1 | ||
|
|
b039a81375 | ||
|
|
46fe9a167e | ||
|
|
79eb971fad | ||
|
|
81e9aa4de4 | ||
|
|
6d3521c240 | ||
|
|
23e0240410 | ||
|
|
1ae24b366f | ||
|
|
2ceb58d0c4 | ||
|
|
e1f63a3346 | ||
|
|
ec0b09450c | ||
|
|
4b78ab5bcd | ||
|
|
ae554a736b | ||
|
|
f842e28b85 | ||
|
|
33aa3f0fc5 | ||
|
|
e4e042e389 | ||
|
|
f3003a97ef | ||
|
|
6550bc97ba | ||
|
|
862de3a9dc | ||
|
|
22407fc897 | ||
|
|
dba6fe8af3 | ||
|
|
ef9500a8f0 | ||
|
|
bf1ea560e9 | ||
|
|
086b59483e | ||
|
|
048bcf19f6 | ||
|
|
8797be9f89 | ||
|
|
cc64d65c2f | ||
|
|
efdb990e56 | ||
|
|
bc7c2cd3f5 | ||
|
|
1584dac00a | ||
|
|
79986e5593 | ||
|
|
b8aa8b3079 | ||
|
|
ced3bafa99 | ||
|
|
755ec552de | ||
|
|
18f9f6c159 | ||
|
|
6da7ed9706 | ||
|
|
ffac5c1299 | ||
|
|
fe5673134f | ||
|
|
1d8fdc09e7 | ||
|
|
7d6cda4916 | ||
|
|
b25cb60259 | ||
|
|
87e98f01cd | ||
|
|
22cda198ae | ||
|
|
d1c06a93df | ||
|
|
eed0d9c8d2 | ||
|
|
bf82fdb678 | ||
|
|
e1e7fbf83d | ||
|
|
c739428c30 | ||
|
|
2a7d2ffccb | ||
|
|
5eceabf810 | ||
|
|
67ad903556 | ||
|
|
36b0802789 | ||
|
|
93fdc18fd4 | ||
|
|
73b0e6c37b | ||
|
|
65aad44464 | ||
|
|
a02cf5beb7 | ||
|
|
b76b42f209 | ||
|
|
ee88b0dc35 | ||
|
|
3dc7706c45 | ||
|
|
9741af2031 | ||
|
|
487b2089a9 | ||
|
|
b28368c859 | ||
|
|
22778e6efd | ||
|
|
3d77685108 | ||
|
|
25899b72d2 | ||
|
|
f877afb74d | ||
|
|
83c76981b2 | ||
|
|
975b53b318 | ||
|
|
2f5ae85d33 | ||
|
|
51878aeca8 | ||
|
|
1d2eb0f903 | ||
|
|
7cbaf06097 | ||
|
|
1059a35bbc | ||
|
|
064e474b0a | ||
|
|
aef2b6b45f | ||
|
|
35a7a3a52b | ||
|
|
e0c6048820 | ||
|
|
ffb12d122f | ||
|
|
b08f8bab71 | ||
|
|
1a05ae2eaa | ||
|
|
961c31a747 | ||
|
|
d1a345bb03 | ||
|
|
236aed112f | ||
|
|
3d7facf6ee | ||
|
|
eee49a4995 | ||
|
|
6de1399cf0 | ||
|
|
15aeb4aec2 | ||
|
|
86f0007768 | ||
|
|
3065d10931 | ||
|
|
4c4189d631 | ||
|
|
015b409f2f | ||
|
|
e2c794ff31 | ||
|
|
2a9b51d836 | ||
|
|
510360a509 | ||
|
|
6b2a4fe8e8 | ||
|
|
49fe90874a | ||
|
|
acbaef1907 | ||
|
|
74101eaf7c | ||
|
|
8ab324988c | ||
|
|
1283461b89 | ||
|
|
38790e2c4b | ||
|
|
aa718b4dce | ||
|
|
2d09dfd34f | ||
|
|
48e4de823a | ||
|
|
65d8403a04 | ||
|
|
a8ac37f517 | ||
|
|
b2c0679a7f | ||
|
|
8db00073b4 | ||
|
|
d36c1769e0 | ||
|
|
53ecb4c1ae | ||
|
|
616dd5c4a5 | ||
|
|
2edb0ad94d | ||
|
|
f8a535c6e8 | ||
|
|
f1bd614770 | ||
|
|
c8965d0f9a | ||
|
|
53bb264375 | ||
|
|
1ea54049d0 | ||
|
|
ca8543348b | ||
|
|
cf87e8ecf5 | ||
|
|
a6afd85526 | ||
|
|
0d4c76a029 | ||
|
|
c3708b3096 | ||
|
|
22a7eaf2e7 | ||
|
|
540def2c39 | ||
|
|
bf90fbc678 | ||
|
|
2b9d260686 | ||
|
|
f6633c8189 | ||
|
|
18f704533f | ||
|
|
aedba5411c | ||
|
|
e83d13848e | ||
|
|
696fad702f | ||
|
|
724a511995 | ||
|
|
90c9c70416 | ||
|
|
f8a4661d05 | ||
|
|
dd494e648a | ||
|
|
c9d6321f38 | ||
|
|
4038b4d17e | ||
|
|
46551e9d65 | ||
|
|
1060eeb197 | ||
|
|
201d30a944 | ||
|
|
fc2a069180 | ||
|
|
392407136d | ||
|
|
ba6573af61 | ||
|
|
8d988f9582 | ||
|
|
f923edc424 | ||
|
|
2712d9ae8b | ||
|
|
3312a042dd | ||
|
|
5040570ea9 | ||
|
|
f5c5d1b1da | ||
|
|
2cd6c2e7e0 | ||
|
|
0daadc954c | ||
|
|
ec98b7d672 | ||
|
|
8c2b6b532d | ||
|
|
71d62012e1 | ||
|
|
41deea90ee | ||
|
|
a81806d3d0 | ||
|
|
5607a114f9 | ||
|
|
e81614b9e9 | ||
|
|
6f094ef215 | ||
|
|
366baea099 | ||
|
|
dc9dcd045d | ||
|
|
10c47ee27c | ||
|
|
8f0240a295 | ||
|
|
fd08c821f9 | ||
|
|
c41c771e9a | ||
|
|
fff5aa3020 | ||
|
|
f1ec270e3e | ||
|
|
a3f2f574c6 | ||
|
|
ec19a97156 | ||
|
|
9a7817a271 | ||
|
|
8a0d5aa38d | ||
|
|
a52869507e | ||
|
|
c77d72b29f | ||
|
|
76d18e7156 | ||
|
|
9e6056551d | ||
|
|
bbea698af3 | ||
|
|
9eec68985d | ||
|
|
cd82f579bd | ||
|
|
93665f49b1 | ||
|
|
dc77d555f9 | ||
|
|
dfe3806d01 | ||
|
|
cfc7710205 | ||
|
|
c60d737928 | ||
|
|
1da149d9e1 | ||
|
|
43ba563a1c | ||
|
|
05cb6048ae | ||
|
|
70d6b32e14 | ||
|
|
75940c1f5d | ||
|
|
1d27a7f93d | ||
|
|
cffcc4c7a5 | ||
|
|
c727c3c441 | ||
|
|
fb4dc77f36 | ||
|
|
9eb7b192b8 | ||
|
|
06d63dda6e | ||
|
|
e6f251011f | ||
|
|
6a813aa33d | ||
|
|
441682b598 | ||
|
|
9c672f6ec1 | ||
|
|
35c05463e7 | ||
|
|
f00cbc0aeb | ||
|
|
ee86d24797 | ||
|
|
58a9324db0 | ||
|
|
e0e8fd6637 | ||
|
|
2416ee04c8 | ||
|
|
91c6ebb06c | ||
|
|
df0ddc0b50 | ||
|
|
2e02abffc0 | ||
|
|
e47957ce6d | ||
|
|
c54e688272 | ||
|
|
37821e6d63 | ||
|
|
a3ee388b66 | ||
|
|
855e913bbd | ||
|
|
78360ece8a | ||
|
|
7c46423727 | ||
|
|
fb74d10573 | ||
|
|
430bcf192f | ||
|
|
cac723dab3 | ||
|
|
617d18e587 | ||
|
|
2b06ceda71 | ||
|
|
1bb4ca22e7 | ||
|
|
24a410ae8f | ||
|
|
673984a7db | ||
|
|
10339090b8 | ||
|
|
b6dcf6bd02 | ||
|
|
280e7bb04d | ||
|
|
03551a5961 | ||
|
|
d474eba53a | ||
|
|
392cb2a714 | ||
|
|
92ac370415 | ||
|
|
c41e3dcb91 | ||
|
|
602d1a5fbc | ||
|
|
cd80884b76 | ||
|
|
bfadc932d7 | ||
|
|
0cd2e150d5 | ||
|
|
5aaaeb05a0 | ||
|
|
26ea0bc360 | ||
|
|
a86d218891 | ||
|
|
6632f883c0 | ||
|
|
66bcae353c | ||
|
|
07d355851e | ||
|
|
8d2f350ad1 | ||
|
|
fc1891320e | ||
|
|
8a9455d901 | ||
|
|
46b6ab7db7 | ||
|
|
958f97232f | ||
|
|
05d064ca8d | ||
|
|
47f88346d2 | ||
|
|
b5fc12fb80 | ||
|
|
83f5080274 | ||
|
|
df50fa2332 | ||
|
|
ad7a1e15b4 | ||
|
|
efe6fd154b | ||
|
|
fb8296524e | ||
|
|
00957a42d4 | ||
|
|
99db89067e | ||
|
|
f1b5a265ab | ||
|
|
451e917e7d | ||
|
|
d443079cf6 | ||
|
|
163e55c0eb | ||
|
|
09f11cf66e | ||
|
|
4ea3002572 | ||
|
|
840cd7b2e1 | ||
|
|
0760528f4a | ||
|
|
7f0fe31881 | ||
|
|
2be8658034 | ||
|
|
494bee1d6b | ||
|
|
0c345e2b09 | ||
|
|
adce8c15bb | ||
|
|
7cd663bbe8 | ||
|
|
85758a2dd2 | ||
|
|
7bc15ec6c1 | ||
|
|
d9d46096dd | ||
|
|
da68f7d31a | ||
|
|
41ed0e670a | ||
|
|
579b36754a | ||
|
|
e50211572f | ||
|
|
6849bfae16 | ||
|
|
c3f1d1a647 | ||
|
|
ac674bd405 | ||
|
|
d5899aacfb | ||
|
|
9e5a8c3fc8 | ||
|
|
83707f7b35 | ||
|
|
ca8df67947 | ||
|
|
3feb6492e6 | ||
|
|
c6744925c4 | ||
|
|
88b2f48493 | ||
|
|
0d3e06e68a | ||
|
|
bf890719ff | ||
|
|
28eae1e7ff | ||
|
|
9f9f4e7fef | ||
|
|
2f6b00b6f7 | ||
|
|
35f55cabf0 | ||
|
|
0201ac24e7 | ||
|
|
731c35540f | ||
|
|
dac62ec560 | ||
|
|
2c7447eaca | ||
|
|
b170b6ec8b | ||
|
|
8a3bdb3685 | ||
|
|
85e8cba7a1 | ||
|
|
56bf9c5612 | ||
|
|
549eb15c32 | ||
|
|
03663c5b28 | ||
|
|
bbd52c0b71 | ||
|
|
995f6be2c4 | ||
|
|
5b42753b8b | ||
|
|
959714a6ef | ||
|
|
79a8017fe9 | ||
|
|
e4a24e1785 | ||
|
|
9b0da20d90 | ||
|
|
db664c61a4 | ||
|
|
c299b86983 | ||
|
|
56e53d7da2 | ||
|
|
d676840258 | ||
|
|
cca37caf33 | ||
|
|
4358687bfa | ||
|
|
ae66c3f289 | ||
|
|
d3bbc245c9 | ||
|
|
5ee1b6ca97 | ||
|
|
c522341136 | ||
|
|
2cebe151f2 | ||
|
|
ecf5b61e86 | ||
|
|
c01ab63744 | ||
|
|
72b324c95b | ||
|
|
0c5abc491d | ||
|
|
a5e2e59385 | ||
|
|
040dd91d2e | ||
|
|
c6c07599c7 | ||
|
|
04ef25b6ff | ||
|
|
05ca7158d6 | ||
|
|
c7e7a0cd16 | ||
|
|
70f7177025 | ||
|
|
c86cdb1805 | ||
|
|
bd15534360 | ||
|
|
e30745f19c | ||
|
|
bca8d6d07b | ||
|
|
0764a4313b | ||
|
|
e0ef6dd8d4 | ||
|
|
3d366c2a4c | ||
|
|
2018e30366 | ||
|
|
303cd8a5af | ||
|
|
2f7af968bf | ||
|
|
543d247af8 | ||
|
|
ca1182e783 | ||
|
|
a34a784b43 | ||
|
|
3bd4b5ccc6 | ||
|
|
f4a013946f | ||
|
|
d2fd829a58 | ||
|
|
bb6f4fff87 | ||
|
|
5ffd57695c | ||
|
|
02ae1f79f7 | ||
|
|
f42b47e65b | ||
|
|
6dc24ab2d7 | ||
|
|
fe0b7533a1 | ||
|
|
b8d861edc1 | ||
|
|
de26a17dc7 | ||
|
|
37907e4110 | ||
|
|
152e085310 | ||
|
|
372b394f5b | ||
|
|
3889052c31 | ||
|
|
43182cb1eb | ||
|
|
de5a39f320 | ||
|
|
58b91befde | ||
|
|
8f976fd980 | ||
|
|
91047ffa30 | ||
|
|
b42064acdb | ||
|
|
7e220b2b9e | ||
|
|
072f51e300 | ||
|
|
af95993d6d | ||
|
|
e6bccc5eff | ||
|
|
1b262d33f3 | ||
|
|
c555bbce3d | ||
|
|
f6d538bb98 | ||
|
|
cbefd8f8ae | ||
|
|
736ee3ffff | ||
|
|
36c583dddf | ||
|
|
70d03b7a1c | ||
|
|
0d85254a19 | ||
|
|
e3376136ca | ||
|
|
f8b4fcdc42 | ||
|
|
6c340dcb65 | ||
|
|
6b467d5b3e | ||
|
|
5372bcc7a2 | ||
|
|
0c9a19e38c | ||
|
|
8b4c7c94b8 | ||
|
|
c4440eab4c | ||
|
|
7349427189 | ||
|
|
89ea25ca08 | ||
|
|
5d652dcaef | ||
|
|
d69788c9df | ||
|
|
69c2fafa7a | ||
|
|
620e3a602d | ||
|
|
ad8dbbb559 | ||
|
|
5a241a8290 | ||
|
|
4a332065d0 | ||
|
|
0e4b70a4a8 | ||
|
|
f1d4fd3e67 | ||
|
|
7b560f9080 | ||
|
|
0ebd921bbb | ||
|
|
206cb51219 | ||
|
|
5e6485c210 | ||
|
|
65b4945548 | ||
|
|
aa98ada141 | ||
|
|
26eeb6578d | ||
|
|
8bb07124f7 | ||
|
|
bce5c447b3 | ||
|
|
34cb17546d | ||
|
|
c1cd1fedf4 | ||
|
|
5defc2a3d2 | ||
|
|
7b2a21994f | ||
|
|
7c06604f16 | ||
|
|
0762c38d35 | ||
|
|
baac7809c5 | ||
|
|
79ed99a940 | ||
|
|
bca0894f73 | ||
|
|
9316bcf307 | ||
|
|
60855643c4 | ||
|
|
650bb4c719 | ||
|
|
2244224b12 | ||
|
|
bbf4d00319 | ||
|
|
6b813b4e2a | ||
|
|
529cb43397 | ||
|
|
6bc898b215 | ||
|
|
1a433de0b4 | ||
|
|
4d802df040 | ||
|
|
04a79175bf | ||
|
|
97656d65ec | ||
|
|
ba28d2e13f | ||
|
|
711992c8e2 | ||
|
|
31624b410a | ||
|
|
00827ce921 | ||
|
|
21d2a51cd3 | ||
|
|
c0384a04f8 | ||
|
|
ee0c4cd194 | ||
|
|
07b13e24fa | ||
|
|
0855f51436 | ||
|
|
70acfb2cfd | ||
|
|
29a2b2032a | ||
|
|
af2efbe480 | ||
|
|
25b0773a94 | ||
|
|
349f6b51a5 | ||
|
|
9917de09af | ||
|
|
884eef32c9 | ||
|
|
16dbf3166d | ||
|
|
be19f8888e | ||
|
|
3bbc86bcf2 | ||
|
|
8b656f15b9 | ||
|
|
453f8b312a | ||
|
|
723bfa70db | ||
|
|
45dd9c5795 | ||
|
|
fa479afdaa | ||
|
|
1dfeb192a3 | ||
|
|
1f9c2add7c | ||
|
|
24fbcd8dea | ||
|
|
db15bf23b8 | ||
|
|
de52ca4785 | ||
|
|
2748a3fbd8 | ||
|
|
dfe36fb702 | ||
|
|
297c829bdc | ||
|
|
bd933badb1 | ||
|
|
0fb4141ce4 | ||
|
|
51de894692 | ||
|
|
7079b5d770 | ||
|
|
41e5812a22 | ||
|
|
8d5f28b33a | ||
|
|
3925bcb94c | ||
|
|
8d1ac8c7f5 | ||
|
|
9f4ad73698 | ||
|
|
0108b5eb88 | ||
|
|
0c6841bdc7 | ||
|
|
c455e501ac | ||
|
|
44c1d8c1e5 | ||
|
|
ff22f43002 | ||
|
|
4e8396dbce | ||
|
|
d38d4efc18 | ||
|
|
a8c68e33db | ||
|
|
903d1b7797 | ||
|
|
5abaf26b5f | ||
|
|
485a377800 | ||
|
|
bd21a08bc9 | ||
|
|
99ae38a232 | ||
|
|
c148e54bbd | ||
|
|
267ab822c2 | ||
|
|
39cdaf5175 | ||
|
|
80818f80a9 | ||
|
|
fde6eee4f4 | ||
|
|
14ec69a160 | ||
|
|
8ebe9d1e16 | ||
|
|
7e66d0bcc1 | ||
|
|
4515e66783 | ||
|
|
1069f485da | ||
|
|
4c4835e869 | ||
|
|
a1faaa133c | ||
|
|
805fd18b7b | ||
|
|
33f7b8479e | ||
|
|
68bd82f1b6 | ||
|
|
13471ae2c4 | ||
|
|
822bf13b7a | ||
|
|
1cce5fdfe1 | ||
|
|
6b2fedb1c2 | ||
|
|
e307ada374 | ||
|
|
4f2628c221 | ||
|
|
0f16066915 | ||
|
|
151d8db98d | ||
|
|
614b26fff6 | ||
|
|
49b2743a37 | ||
|
|
8e37de19c9 | ||
|
|
38bda92bdc | ||
|
|
83ba6638a1 | ||
|
|
4832ecf3e7 | ||
|
|
2e8ed97355 | ||
|
|
d98839fc19 | ||
|
|
0f71838fdf | ||
|
|
b6de656cf1 | ||
|
|
75555c470b | ||
|
|
4d0b14fbb4 | ||
|
|
1f9922a5aa | ||
|
|
b3f3b70b90 | ||
|
|
924800b7df | ||
|
|
d27da57b02 | ||
|
|
f1a01aed7e | ||
|
|
c1a5771fcd | ||
|
|
8ac5c36735 | ||
|
|
6355896584 | ||
|
|
6216ce455f | ||
|
|
c0832995ae | ||
|
|
9469b20cbd | ||
|
|
573457c03f | ||
|
|
5c395424c6 | ||
|
|
f6d53df282 | ||
|
|
e4374b1d56 | ||
|
|
7302ddaba5 | ||
|
|
7456514816 | ||
|
|
d9ad4cf2fc | ||
|
|
8b4efbed06 | ||
|
|
10131aa8a0 | ||
|
|
23dc85c1de | ||
|
|
338c6b5a5c | ||
|
|
c13ebce2f6 | ||
|
|
b6ccd7ffbe | ||
|
|
ad0794cc59 | ||
|
|
6961cb7440 | ||
|
|
9868edb138 | ||
|
|
e822fad505 | ||
|
|
3ab5427019 | ||
|
|
7afb6fa3e3 | ||
|
|
29dff7ba1a | ||
|
|
329ee8d9f1 | ||
|
|
f70e0003f8 | ||
|
|
bb0eb29c82 | ||
|
|
47bba71d7f | ||
|
|
6b8921c8c5 | ||
|
|
7d09579e3f | ||
|
|
e5c9a24c33 | ||
|
|
e7626befc5 | ||
|
|
905d31442c | ||
|
|
963001ba1a | ||
|
|
75649c49d5 | ||
|
|
92f5f8dced | ||
|
|
6a55ec6955 | ||
|
|
e470786fb9 | ||
|
|
6bb001e416 | ||
|
|
50d773988b | ||
|
|
d2239427f2 | ||
|
|
24a7d4f816 | ||
|
|
a4f9621473 | ||
|
|
437b880b3e | ||
|
|
bd6a68bfe5 | ||
|
|
a5a244767a | ||
|
|
55189200a4 |
12
.flooignore
Normal file
12
.flooignore
Normal file
@@ -0,0 +1,12 @@
|
||||
#*
|
||||
*.o
|
||||
*.pyc
|
||||
*.pyo
|
||||
*~
|
||||
extern/
|
||||
node_modules/
|
||||
tmp/
|
||||
data/
|
||||
vendor/
|
||||
public_gen/
|
||||
dist/
|
||||
23
.github/ISSUE_TEMPLATE.md
vendored
23
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,12 +1,17 @@
|
||||
Thank you! For helping us make Grafana even better.
|
||||
* **I'm submitting a ...**
|
||||
- [ ] Bug report
|
||||
- [ ] Feature request
|
||||
- [ ] Question / Support request: **Please do not** open a github issue. [Support Options](http://grafana.org/support/)
|
||||
|
||||
To help us respond to your issues faster, please make sure to add as much information as possible.
|
||||
Please include this information:
|
||||
- What Grafana version are you using?
|
||||
- What datasource are you using?
|
||||
- What OS are you running grafana on?
|
||||
- What did you do?
|
||||
- What was the expected result?
|
||||
- What happened instead?
|
||||
|
||||
If this issue is about a plugin, please open the issue in that repository.
|
||||
**IMPORTANT** If it relates to metric data viz:
|
||||
- An image or text representation of your metric query
|
||||
- The raw query and response for the network request (check this in chrome dev tools network tab, here you can see metric requests and other request, please include the request body and request response)
|
||||
|
||||
Start your issues title with [Feature Request] / [Bug] / [Question] or no tag if your unsure.
|
||||
|
||||
Ex
|
||||
* What grafana version are you using?
|
||||
* What datasource are you using?
|
||||
* What OS are you running grafana on?
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"validateIndentation": 2
|
||||
}
|
||||
}
|
||||
|
||||
114
CHANGELOG.md
114
CHANGELOG.md
@@ -1,7 +1,119 @@
|
||||
# 3.0.0-beta3 (unreleased)
|
||||
# 3.1.0-beta1 (2016-06-23)
|
||||
|
||||
### Enhancements
|
||||
* **Dashboard Export/Import**: Dashboard export now templetize data sources and constant variables, users pick these on import, closes [#5084](https://github.com/grafana/grafana/issues/5084)
|
||||
* **Dashboard Url**: Time range changes updates url, closes [#458](https://github.com/grafana/grafana/issues/458)
|
||||
* **Dashboard Url**: Template variable change updates url, closes [#5002](https://github.com/grafana/grafana/issues/5002)
|
||||
* **Singlestat**: Add support for range to text mappings, closes [#1319](https://github.com/grafana/grafana/issues/1319)
|
||||
* **Graph**: Adds sort order options for graph tooltip, closes [#1189](https://github.com/grafana/grafana/issues/1189)
|
||||
* **Theme**: Add default theme to config file [#5011](https://github.com/grafana/grafana/pull/5011)
|
||||
* **Page Footer**: Added page footer with links to docs, shows Grafana version and info if new version is available, closes [#4889](https://github.com/grafana/grafana/pull/4889)
|
||||
* **InfluxDB**: Add spread function, closes [#5211](https://github.com/grafana/grafana/issues/5211)
|
||||
* **Scripts**: Use restart instead of start for deb package script, closes [#5282](https://github.com/grafana/grafana/pull/5282)
|
||||
* **Logging**: Moved to structured logging lib, and moved to component specific level filters via config file, closes [#4590](https://github.com/grafana/grafana/issues/4590)
|
||||
* **OpenTSDB**: Support nested template variables in tag_values function, closes [4398](https://github.com/grafana/grafana/issues/4398)
|
||||
* **Datasource**: Pending data source requests are cancelled before new ones are issues (Graphite & Prometheus), closes [5321](https://github.com/grafana/grafana/issues/5321)
|
||||
|
||||
### Breaking changes
|
||||
* **Logging** : Changed default logging output format (now structured into message, and key value pairs, with logger key acting as component). You can also no change in config to json log ouput.
|
||||
* **Graphite** : The Graph panel no longer have a Graphite PNG option. closes [#5367](https://github.com/grafana/grafana/issues/5367)
|
||||
|
||||
### Bug fixes
|
||||
* **PNG rendering**: Fixed phantomjs rendering and y-axis label rotation. fixes [#5220](https://github.com/grafana/grafana/issues/5220)
|
||||
* **CLI**: The cli tool now supports reading plugin.json from dist/plugin.json. fixes [#5410](https://github.com/grafana/grafana/issues/5410)
|
||||
|
||||
# 3.0.4 Patch release (2016-05-25)
|
||||
* **Panel**: Fixed blank dashboard issue when switching to other dashboard while in fullscreen edit mode, fixes [#5163](https://github.com/grafana/grafana/pull/5163)
|
||||
* **Templating**: Fixed issue with nested multi select variables and cascading and updating child variable selection state, fixes [#4861](https://github.com/grafana/grafana/pull/4861)
|
||||
* **Templating**: Fixed issue with using templated data source in another template variable query, fixes [#5165](https://github.com/grafana/grafana/pull/5165)
|
||||
* **Singlestat gauge**: Fixed issue with gauge render position, fixes [#5143](https://github.com/grafana/grafana/pull/5143)
|
||||
* **Home dashboard**: Fixes broken home dashboard api, fixes [#5167](https://github.com/grafana/grafana/issues/5167)
|
||||
|
||||
# 3.0.3 Patch release (2016-05-23)
|
||||
* **Annotations**: Annotations can now use a template variable as data source, closes [#5054](https://github.com/grafana/grafana/issues/5054)
|
||||
* **Time picker**: Fixed issue timepicker and UTC when reading time from URL, fixes [#5078](https://github.com/grafana/grafana/issues/5078)
|
||||
* **CloudWatch**: Support for Multiple Account by AssumeRole, closes [#3522](https://github.com/grafana/grafana/issues/3522)
|
||||
* **Singlestat**: Fixed alignment and minium height issue, fixes [#5113](https://github.com/grafana/grafana/issues/5113), fixes [#4679](https://github.com/grafana/grafana/issues/4679)
|
||||
* **Share modal**: Fixed link when using grafana under dashboard sub url, fixes [#5109](https://github.com/grafana/grafana/issues/5109)
|
||||
* **Prometheus**: Fixed bug in query editor that caused it not to load when reloading page, fixes [#5107](https://github.com/grafana/grafana/issues/5107)
|
||||
* **Elasticsearch**: Fixed bug when template variable query returns numeric values, fixes [#5097](https://github.com/grafana/grafana/issues/5097), fixes [#5088](https://github.com/grafana/grafana/issues/5088)
|
||||
* **Logging**: Fixed issue with reading logging level value, fixes [#5079](https://github.com/grafana/grafana/issues/5079)
|
||||
* **Timepicker**: Fixed issue with timepicker and UTC when reading time from URL, fixes [#5078](https://github.com/grafana/grafana/issues/5078)
|
||||
* **Docs**: Added docs for org & user preferences HTTP API, closes [#5069](https://github.com/grafana/grafana/issues/5069)
|
||||
* **Plugin list panel**: Now shows correct enable state for apps when not enabled, fixes [#5068](https://github.com/grafana/grafana/issues/5068)
|
||||
* **Elasticsearch**: Templating & Annotation queries that use template variables are now formatted correctly, fixes [#5135](https://github.com/grafana/grafana/issues/5135)
|
||||
|
||||
# 3.0.2 Patch release (2016-05-16)
|
||||
|
||||
* **Templating**: Fixed issue mixing row repeat and panel repeats, fixes [#4988](https://github.com/grafana/grafana/issues/4988)
|
||||
* **Templating**: Fixed issue detecting dependencies in nested variables, fixes [#4987](https://github.com/grafana/grafana/issues/4987), fixes [#4986](https://github.com/grafana/grafana/issues/4986)
|
||||
* **Graph**: Fixed broken PNG rendering in graph panel, fixes [#5025](https://github.com/grafana/grafana/issues/5025)
|
||||
* **Graph**: Fixed broken xaxis on graph panel, fixes [#5024](https://github.com/grafana/grafana/issues/5024)
|
||||
|
||||
* **Influxdb**: Fixes crash when hiding middle serie, fixes [#5005](https://github.com/grafana/grafana/issues/5005)
|
||||
|
||||
# 3.0.1 Stable (2016-05-11)
|
||||
|
||||
### Bug fixes
|
||||
* **Templating**: Fixed issue with new data source variable not persisting current selected value, fixes [#4934](https://github.com/grafana/grafana/issues/4934)
|
||||
|
||||
# 3.0.0-beta7 (2016-05-02)
|
||||
|
||||
### Bug fixes
|
||||
* **Dashboard title**: Fixed max dashboard title width (media query) for large screens, fixes [#4859](https://github.com/grafana/grafana/issues/4859)
|
||||
* **Annotations**: Fixed issue with entering annotation edit view, fixes [#4857](https://github.com/grafana/grafana/issues/4857)
|
||||
* **Remove query**: Fixed issue with removing query for data sources without collapsable query editors, fixes [#4856](https://github.com/grafana/grafana/issues/4856)
|
||||
* **Graphite PNG**: Fixed issue graphite png rendering option, fixes [#4864](https://github.com/grafana/grafana/issues/4864)
|
||||
* **InfluxDB**: Fixed issue missing plus group by iconn, fixes [#4862](https://github.com/grafana/grafana/issues/4862)
|
||||
* **Graph**: Fixes missing line mode for thresholds, fixes [#4902](https://github.com/grafana/grafana/pull/4902)
|
||||
|
||||
### Enhancements
|
||||
* **InfluxDB**: Added new functions moving_average and difference to query editor, closes [#4698](https://github.com/grafana/grafana/issues/4698)
|
||||
|
||||
# 3.0.0-beta6 (2016-04-29)
|
||||
|
||||
### Enhancements
|
||||
* **Singlestat**: Support for gauges in singlestat panel. closes [#3688](https://github.com/grafana/grafana/pull/3688)
|
||||
* **Templating**: Support for data source as variable, closes [#816](https://github.com/grafana/grafana/pull/816)
|
||||
|
||||
### Bug fixes
|
||||
* **InfluxDB 0.12**: Fixed issue templating and `show tag values` query only returning tags for first measurement, fixes [#4726](https://github.com/grafana/grafana/issues/4726)
|
||||
* **Templating**: Fixed issue with regex formating when matching multiple values, fixes [#4755](https://github.com/grafana/grafana/issues/4755)
|
||||
* **Templating**: Fixed issue with custom all value and escaping, fixes [#4736](https://github.com/grafana/grafana/issues/4736)
|
||||
* **Dashlist**: Fixed issue dashboard list panel and caching tags, fixes [#4768](https://github.com/grafana/grafana/issues/4768)
|
||||
* **Graph**: Fixed issue with unneeded scrollbar in legend for Firefox, fixes [#4760](https://github.com/grafana/grafana/issues/4760)
|
||||
* **Table panel**: Fixed issue table panel formating string array properties, fixes [#4791](https://github.com/grafana/grafana/issues/4791)
|
||||
* **grafana-cli**: Improve error message when failing to install plugins due to corrupt response, fixes [#4651](https://github.com/grafana/grafana/issues/4651)
|
||||
* **Singlestat**: Fixes prefix an postfix for gauges, fixes [#4812](https://github.com/grafana/grafana/issues/4812)
|
||||
* **Singlestat**: Fixes auto-refresh on change for some options, fixes [#4809](https://github.com/grafana/grafana/issues/4809)
|
||||
|
||||
### Breaking changes
|
||||
**Data Source Query Editors**: Issue [#3900](https://github.com/grafana/grafana/issues/3900)
|
||||
|
||||
Query editors have been updated to use the new form styles. External data source plugins needs to be
|
||||
updated to work. Sorry to introduce breaking change this late in beta phase. We wanted to get this change
|
||||
in before 3.0 stable is released so we don't have to break data sources in next release (3.1). If you are
|
||||
a data source plugin author and want help for how the new form styles work please ask for help in
|
||||
slack channel (link to slack channel in readme).
|
||||
|
||||
# 3.0.0-beta5 (2016-04-15)
|
||||
|
||||
### Bug fixes
|
||||
* **grafana-cli**: Fixed issue grafana-cli tool, did not detect the right plugin dir, fixes [#4723](https://github.com/grafana/grafana/issues/4723)
|
||||
* **Graph**: Fixed issue with light theme text color issue in tooltip, fixes [#4702](https://github.com/grafana/grafana/issues/4702)
|
||||
* **Snapshot**: Fixed issue with empty snapshots, fixes [#4706](https://github.com/grafana/grafana/issues/4706)
|
||||
|
||||
# 3.0.0-beta4 (2016-04-13)
|
||||
|
||||
### Bug fixes
|
||||
* **Home dashboard**: Fixed issue with permission denied error on home dashboard, fixes [#4686](https://github.com/grafana/grafana/issues/4686)
|
||||
* **Templating**: Fixed issue templating variables that use regex extraction, fixes [#4672](https://github.com/grafana/grafana/issues/4672)
|
||||
|
||||
# 3.0.0-beta3 (2016-04-12)
|
||||
|
||||
### Enhancements
|
||||
* **InfluxDB**: Changed multi query encoding to work with InfluxDB 0.11 & 0.12, closes [#4533](https://github.com/grafana/grafana/issues/4533)
|
||||
* **Timepicker**: Add arrows and shortcuts for moving back and forth in current dashboard, closes [#119](https://github.com/grafana/grafana/issues/119)
|
||||
|
||||
### Bug fixes
|
||||
* **Postgres**: Fixed page render crash when using postgres, fixes [#4558](https://github.com/grafana/grafana/issues/4558)
|
||||
|
||||
23
Godeps/Godeps.json
generated
23
Godeps/Godeps.json
generated
@@ -125,6 +125,11 @@
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/sts",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/bmizerany/assert",
|
||||
"Comment": "release.r60-6-ge17e998",
|
||||
@@ -200,6 +205,11 @@
|
||||
"Comment": "v1.2-171-g267b128",
|
||||
"Rev": "267b128680c46286b9ca13475c3cca5de8f79bd7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-stack/stack",
|
||||
"Comment": "v1.5.2",
|
||||
"Rev": "100eb0c0a9c5b306ca2fb4f165df21d80ada4b82"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-xorm/core",
|
||||
"Comment": "v0.4.4-7-g9e608f7",
|
||||
@@ -222,6 +232,16 @@
|
||||
"ImportPath": "github.com/hashicorp/go-version",
|
||||
"Rev": "7e3c02b30806fa5779d3bdfc152ce4c6f40e7b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/log15",
|
||||
"Comment": "v2.3-61-g20bca5a",
|
||||
"Rev": "20bca5a7a57282e241fac83ec9ea42538027f1c1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/log15/term",
|
||||
"Comment": "v2.3-61-g20bca5a",
|
||||
"Rev": "20bca5a7a57282e241fac83ec9ea42538027f1c1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jmespath/go-jmespath",
|
||||
"Comment": "0.2.2",
|
||||
@@ -276,7 +296,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-sqlite3",
|
||||
"Rev": "e28cd440fabdd39b9520344bc26829f61db40ece"
|
||||
"Comment": "v1.1.0-67-g7204887",
|
||||
"Rev": "7204887cf3a42df1cfaa5505dc3a3427f6dded8b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rainycape/unidecode",
|
||||
|
||||
1127
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/api.go
generated
vendored
Normal file
1127
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations.go
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package sts
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws/request"
|
||||
|
||||
func init() {
|
||||
initRequest = func(r *request.Request) {
|
||||
switch r.Operation.Name {
|
||||
case opAssumeRoleWithSAML, opAssumeRoleWithWebIdentity:
|
||||
r.Handlers.Sign.Clear() // these operations are unsigned
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations_test.go
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations_test.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package sts_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
var svc = sts.New(unit.Session, &aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})
|
||||
|
||||
func TestUnsignedRequest_AssumeRoleWithSAML(t *testing.T) {
|
||||
req, _ := svc.AssumeRoleWithSAMLRequest(&sts.AssumeRoleWithSAMLInput{
|
||||
PrincipalArn: aws.String("ARN01234567890123456789"),
|
||||
RoleArn: aws.String("ARN01234567890123456789"),
|
||||
SAMLAssertion: aws.String("ASSERT"),
|
||||
})
|
||||
|
||||
err := req.Sign()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", req.HTTPRequest.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
func TestUnsignedRequest_AssumeRoleWithWebIdentity(t *testing.T) {
|
||||
req, _ := svc.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
||||
RoleArn: aws.String("ARN01234567890123456789"),
|
||||
RoleSessionName: aws.String("SESSION"),
|
||||
WebIdentityToken: aws.String("TOKEN"),
|
||||
})
|
||||
|
||||
err := req.Sign()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", req.HTTPRequest.Header.Get("Authorization"))
|
||||
}
|
||||
149
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/examples_test.go
generated
vendored
Normal file
149
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/examples_test.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package sts_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
var _ time.Duration
|
||||
var _ bytes.Buffer
|
||||
|
||||
func ExampleSTS_AssumeRole() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.AssumeRoleInput{
|
||||
RoleArn: aws.String("arnType"), // Required
|
||||
RoleSessionName: aws.String("roleSessionNameType"), // Required
|
||||
DurationSeconds: aws.Int64(1),
|
||||
ExternalId: aws.String("externalIdType"),
|
||||
Policy: aws.String("sessionPolicyDocumentType"),
|
||||
SerialNumber: aws.String("serialNumberType"),
|
||||
TokenCode: aws.String("tokenCodeType"),
|
||||
}
|
||||
resp, err := svc.AssumeRole(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func ExampleSTS_AssumeRoleWithSAML() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.AssumeRoleWithSAMLInput{
|
||||
PrincipalArn: aws.String("arnType"), // Required
|
||||
RoleArn: aws.String("arnType"), // Required
|
||||
SAMLAssertion: aws.String("SAMLAssertionType"), // Required
|
||||
DurationSeconds: aws.Int64(1),
|
||||
Policy: aws.String("sessionPolicyDocumentType"),
|
||||
}
|
||||
resp, err := svc.AssumeRoleWithSAML(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func ExampleSTS_AssumeRoleWithWebIdentity() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.AssumeRoleWithWebIdentityInput{
|
||||
RoleArn: aws.String("arnType"), // Required
|
||||
RoleSessionName: aws.String("roleSessionNameType"), // Required
|
||||
WebIdentityToken: aws.String("clientTokenType"), // Required
|
||||
DurationSeconds: aws.Int64(1),
|
||||
Policy: aws.String("sessionPolicyDocumentType"),
|
||||
ProviderId: aws.String("urlType"),
|
||||
}
|
||||
resp, err := svc.AssumeRoleWithWebIdentity(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func ExampleSTS_DecodeAuthorizationMessage() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.DecodeAuthorizationMessageInput{
|
||||
EncodedMessage: aws.String("encodedMessageType"), // Required
|
||||
}
|
||||
resp, err := svc.DecodeAuthorizationMessage(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func ExampleSTS_GetFederationToken() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.GetFederationTokenInput{
|
||||
Name: aws.String("userNameType"), // Required
|
||||
DurationSeconds: aws.Int64(1),
|
||||
Policy: aws.String("sessionPolicyDocumentType"),
|
||||
}
|
||||
resp, err := svc.GetFederationToken(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func ExampleSTS_GetSessionToken() {
|
||||
svc := sts.New(session.New())
|
||||
|
||||
params := &sts.GetSessionTokenInput{
|
||||
DurationSeconds: aws.Int64(1),
|
||||
SerialNumber: aws.String("serialNumberType"),
|
||||
TokenCode: aws.String("tokenCodeType"),
|
||||
}
|
||||
resp, err := svc.GetSessionToken(params)
|
||||
|
||||
if err != nil {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Pretty-print the response data.
|
||||
fmt.Println(resp)
|
||||
}
|
||||
130
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/service.go
generated
vendored
Normal file
130
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/service.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package sts
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
|
||||
// The AWS Security Token Service (STS) is a web service that enables you to
|
||||
// request temporary, limited-privilege credentials for AWS Identity and Access
|
||||
// Management (IAM) users or for users that you authenticate (federated users).
|
||||
// This guide provides descriptions of the STS API. For more detailed information
|
||||
// about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html).
|
||||
//
|
||||
// As an alternative to using the API, you can use one of the AWS SDKs, which
|
||||
// consist of libraries and sample code for various programming languages and
|
||||
// platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient
|
||||
// way to create programmatic access to STS. For example, the SDKs take care
|
||||
// of cryptographically signing requests, managing errors, and retrying requests
|
||||
// automatically. For information about the AWS SDKs, including how to download
|
||||
// and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/).
|
||||
// For information about setting up signatures and authorization through the
|
||||
// API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html"
|
||||
// target="_blank) in the AWS General Reference. For general information about
|
||||
// the Query API, go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html"
|
||||
// target="_blank) in Using IAM. For information about using security tokens
|
||||
// with other AWS products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html)
|
||||
// in the Using IAM.
|
||||
//
|
||||
// If you're new to AWS and need additional technical information about a specific
|
||||
// AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/
|
||||
// (http://aws.amazon.com/documentation/" target="_blank).
|
||||
//
|
||||
// Endpoints
|
||||
//
|
||||
// The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com
|
||||
// that maps to the US East (N. Virginia) region. Additional regions are available,
|
||||
// but must first be activated in the AWS Management Console before you can
|
||||
// use a different region's endpoint. For more information about activating
|
||||
// a region for STS see Activating STS in a New Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||
// in the Using IAM.
|
||||
//
|
||||
// For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region)
|
||||
// in the AWS General Reference.
|
||||
//
|
||||
// Recording API requests
|
||||
//
|
||||
// STS supports AWS CloudTrail, which is a service that records AWS calls for
|
||||
// your AWS account and delivers log files to an Amazon S3 bucket. By using
|
||||
// information collected by CloudTrail, you can determine what requests were
|
||||
// successfully made to STS, who made the request, when it was made, and so
|
||||
// on. To learn more about CloudTrail, including how to turn it on and find
|
||||
// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html).
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type STS struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "sts"
|
||||
|
||||
// New creates a new instance of the STS client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a STS client from just a session.
|
||||
// svc := sts.New(mySession)
|
||||
//
|
||||
// // Create a STS client with additional configuration
|
||||
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *STS {
|
||||
svc := &STS{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2011-06-15",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
|
||||
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a STS operation and runs any
|
||||
// custom request initialization.
|
||||
func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||
req := c.NewRequest(op, params, data)
|
||||
|
||||
// Run custom request initialization if present
|
||||
if initRequest != nil {
|
||||
initRequest(req)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
38
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
// Package stsiface provides an interface for the AWS Security Token Service.
|
||||
package stsiface
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
// STSAPI is the interface type for sts.STS.
|
||||
type STSAPI interface {
|
||||
AssumeRoleRequest(*sts.AssumeRoleInput) (*request.Request, *sts.AssumeRoleOutput)
|
||||
|
||||
AssumeRole(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||
|
||||
AssumeRoleWithSAMLRequest(*sts.AssumeRoleWithSAMLInput) (*request.Request, *sts.AssumeRoleWithSAMLOutput)
|
||||
|
||||
AssumeRoleWithSAML(*sts.AssumeRoleWithSAMLInput) (*sts.AssumeRoleWithSAMLOutput, error)
|
||||
|
||||
AssumeRoleWithWebIdentityRequest(*sts.AssumeRoleWithWebIdentityInput) (*request.Request, *sts.AssumeRoleWithWebIdentityOutput)
|
||||
|
||||
AssumeRoleWithWebIdentity(*sts.AssumeRoleWithWebIdentityInput) (*sts.AssumeRoleWithWebIdentityOutput, error)
|
||||
|
||||
DecodeAuthorizationMessageRequest(*sts.DecodeAuthorizationMessageInput) (*request.Request, *sts.DecodeAuthorizationMessageOutput)
|
||||
|
||||
DecodeAuthorizationMessage(*sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error)
|
||||
|
||||
GetFederationTokenRequest(*sts.GetFederationTokenInput) (*request.Request, *sts.GetFederationTokenOutput)
|
||||
|
||||
GetFederationToken(*sts.GetFederationTokenInput) (*sts.GetFederationTokenOutput, error)
|
||||
|
||||
GetSessionTokenRequest(*sts.GetSessionTokenInput) (*request.Request, *sts.GetSessionTokenOutput)
|
||||
|
||||
GetSessionToken(*sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error)
|
||||
}
|
||||
|
||||
var _ STSAPI = (*sts.STS)(nil)
|
||||
16
Godeps/_workspace/src/github.com/go-stack/stack/.travis.yml
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/go-stack/stack/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
|
||||
script:
|
||||
- goveralls -service=travis-ci
|
||||
13
Godeps/_workspace/src/github.com/go-stack/stack/LICENSE.md
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/go-stack/stack/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright 2014 Chris Hines
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
38
Godeps/_workspace/src/github.com/go-stack/stack/README.md
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/go-stack/stack/README.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
[](https://godoc.org/github.com/go-stack/stack)
|
||||
[](https://goreportcard.com/report/go-stack/stack)
|
||||
[](https://travis-ci.org/go-stack/stack)
|
||||
[](https://coveralls.io/github/go-stack/stack?branch=master)
|
||||
|
||||
# stack
|
||||
|
||||
Package stack implements utilities to capture, manipulate, and format call
|
||||
stacks. It provides a simpler API than package runtime.
|
||||
|
||||
The implementation takes care of the minutia and special cases of interpreting
|
||||
the program counter (pc) values returned by runtime.Callers.
|
||||
|
||||
## Versioning
|
||||
|
||||
Package stack publishes releases via [semver](http://semver.org/) compatible Git
|
||||
tags prefixed with a single 'v'. The master branch always contains the latest
|
||||
release. The develop branch contains unreleased commits.
|
||||
|
||||
## Formatting
|
||||
|
||||
Package stack's types implement fmt.Formatter, which provides a simple and
|
||||
flexible way to declaratively configure formatting when used with logging or
|
||||
error tracking packages.
|
||||
|
||||
```go
|
||||
func DoTheThing() {
|
||||
c := stack.Caller(0)
|
||||
log.Print(c) // "source.go:10"
|
||||
log.Printf("%+v", c) // "pkg/path/source.go:10"
|
||||
log.Printf("%n", c) // "DoTheThing"
|
||||
|
||||
s := stack.Trace().TrimRuntime()
|
||||
log.Print(s) // "[source.go:15 caller.go:42 main.go:14]"
|
||||
}
|
||||
```
|
||||
|
||||
See the docs for all of the supported formatting options.
|
||||
349
Godeps/_workspace/src/github.com/go-stack/stack/stack.go
generated
vendored
Normal file
349
Godeps/_workspace/src/github.com/go-stack/stack/stack.go
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
// Package stack implements utilities to capture, manipulate, and format call
|
||||
// stacks. It provides a simpler API than package runtime.
|
||||
//
|
||||
// The implementation takes care of the minutia and special cases of
|
||||
// interpreting the program counter (pc) values returned by runtime.Callers.
|
||||
//
|
||||
// Package stack's types implement fmt.Formatter, which provides a simple and
|
||||
// flexible way to declaratively configure formatting when used with logging
|
||||
// or error tracking packages.
|
||||
package stack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Call records a single function invocation from a goroutine stack.
|
||||
type Call struct {
|
||||
fn *runtime.Func
|
||||
pc uintptr
|
||||
}
|
||||
|
||||
// Caller returns a Call from the stack of the current goroutine. The argument
|
||||
// skip is the number of stack frames to ascend, with 0 identifying the
|
||||
// calling function.
|
||||
func Caller(skip int) Call {
|
||||
var pcs [2]uintptr
|
||||
n := runtime.Callers(skip+1, pcs[:])
|
||||
|
||||
var c Call
|
||||
|
||||
if n < 2 {
|
||||
return c
|
||||
}
|
||||
|
||||
c.pc = pcs[1]
|
||||
if runtime.FuncForPC(pcs[0]) != sigpanic {
|
||||
c.pc--
|
||||
}
|
||||
c.fn = runtime.FuncForPC(c.pc)
|
||||
return c
|
||||
}
|
||||
|
||||
// String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", c).
|
||||
func (c Call) String() string {
|
||||
return fmt.Sprint(c)
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler. It formats the Call the same
|
||||
// as fmt.Sprintf("%v", c).
|
||||
func (c Call) MarshalText() ([]byte, error) {
|
||||
if c.fn == nil {
|
||||
return nil, ErrNoFunc
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
fmt.Fprint(&buf, c)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ErrNoFunc means that the Call has a nil *runtime.Func. The most likely
|
||||
// cause is a Call with the zero value.
|
||||
var ErrNoFunc = errors.New("no call stack information")
|
||||
|
||||
// Format implements fmt.Formatter with support for the following verbs.
|
||||
//
|
||||
// %s source file
|
||||
// %d line number
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// It accepts the '+' and '#' flags for most of the verbs as follows.
|
||||
//
|
||||
// %+s path of source file relative to the compile time GOPATH
|
||||
// %#s full path of source file
|
||||
// %+n import path qualified function name
|
||||
// %+v equivalent to %+s:%d
|
||||
// %#v equivalent to %#s:%d
|
||||
func (c Call) Format(s fmt.State, verb rune) {
|
||||
if c.fn == nil {
|
||||
fmt.Fprintf(s, "%%!%c(NOFUNC)", verb)
|
||||
return
|
||||
}
|
||||
|
||||
switch verb {
|
||||
case 's', 'v':
|
||||
file, line := c.fn.FileLine(c.pc)
|
||||
switch {
|
||||
case s.Flag('#'):
|
||||
// done
|
||||
case s.Flag('+'):
|
||||
file = file[pkgIndex(file, c.fn.Name()):]
|
||||
default:
|
||||
const sep = "/"
|
||||
if i := strings.LastIndex(file, sep); i != -1 {
|
||||
file = file[i+len(sep):]
|
||||
}
|
||||
}
|
||||
io.WriteString(s, file)
|
||||
if verb == 'v' {
|
||||
buf := [7]byte{':'}
|
||||
s.Write(strconv.AppendInt(buf[:1], int64(line), 10))
|
||||
}
|
||||
|
||||
case 'd':
|
||||
_, line := c.fn.FileLine(c.pc)
|
||||
buf := [6]byte{}
|
||||
s.Write(strconv.AppendInt(buf[:0], int64(line), 10))
|
||||
|
||||
case 'n':
|
||||
name := c.fn.Name()
|
||||
if !s.Flag('+') {
|
||||
const pathSep = "/"
|
||||
if i := strings.LastIndex(name, pathSep); i != -1 {
|
||||
name = name[i+len(pathSep):]
|
||||
}
|
||||
const pkgSep = "."
|
||||
if i := strings.Index(name, pkgSep); i != -1 {
|
||||
name = name[i+len(pkgSep):]
|
||||
}
|
||||
}
|
||||
io.WriteString(s, name)
|
||||
}
|
||||
}
|
||||
|
||||
// PC returns the program counter for this call frame; multiple frames may
|
||||
// have the same PC value.
|
||||
func (c Call) PC() uintptr {
|
||||
return c.pc
|
||||
}
|
||||
|
||||
// name returns the import path qualified name of the function containing the
|
||||
// call.
|
||||
func (c Call) name() string {
|
||||
if c.fn == nil {
|
||||
return "???"
|
||||
}
|
||||
return c.fn.Name()
|
||||
}
|
||||
|
||||
func (c Call) file() string {
|
||||
if c.fn == nil {
|
||||
return "???"
|
||||
}
|
||||
file, _ := c.fn.FileLine(c.pc)
|
||||
return file
|
||||
}
|
||||
|
||||
func (c Call) line() int {
|
||||
if c.fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := c.fn.FileLine(c.pc)
|
||||
return line
|
||||
}
|
||||
|
||||
// CallStack records a sequence of function invocations from a goroutine
|
||||
// stack.
|
||||
type CallStack []Call
|
||||
|
||||
// String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", cs).
|
||||
func (cs CallStack) String() string {
|
||||
return fmt.Sprint(cs)
|
||||
}
|
||||
|
||||
var (
|
||||
openBracketBytes = []byte("[")
|
||||
closeBracketBytes = []byte("]")
|
||||
spaceBytes = []byte(" ")
|
||||
)
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler. It formats the CallStack the
|
||||
// same as fmt.Sprintf("%v", cs).
|
||||
func (cs CallStack) MarshalText() ([]byte, error) {
|
||||
buf := bytes.Buffer{}
|
||||
buf.Write(openBracketBytes)
|
||||
for i, pc := range cs {
|
||||
if pc.fn == nil {
|
||||
return nil, ErrNoFunc
|
||||
}
|
||||
if i > 0 {
|
||||
buf.Write(spaceBytes)
|
||||
}
|
||||
fmt.Fprint(&buf, pc)
|
||||
}
|
||||
buf.Write(closeBracketBytes)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter by printing the CallStack as square brackets
|
||||
// ([, ]) surrounding a space separated list of Calls each formatted with the
|
||||
// supplied verb and options.
|
||||
func (cs CallStack) Format(s fmt.State, verb rune) {
|
||||
s.Write(openBracketBytes)
|
||||
for i, pc := range cs {
|
||||
if i > 0 {
|
||||
s.Write(spaceBytes)
|
||||
}
|
||||
pc.Format(s, verb)
|
||||
}
|
||||
s.Write(closeBracketBytes)
|
||||
}
|
||||
|
||||
// findSigpanic intentionally executes faulting code to generate a stack trace
|
||||
// containing an entry for runtime.sigpanic.
|
||||
func findSigpanic() *runtime.Func {
|
||||
var fn *runtime.Func
|
||||
var p *int
|
||||
func() int {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
var pcs [512]uintptr
|
||||
n := runtime.Callers(2, pcs[:])
|
||||
for _, pc := range pcs[:n] {
|
||||
f := runtime.FuncForPC(pc)
|
||||
if f.Name() == "runtime.sigpanic" {
|
||||
fn = f
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
// intentional nil pointer dereference to trigger sigpanic
|
||||
return *p
|
||||
}()
|
||||
return fn
|
||||
}
|
||||
|
||||
var sigpanic = findSigpanic()
|
||||
|
||||
// Trace returns a CallStack for the current goroutine with element 0
|
||||
// identifying the calling function.
|
||||
func Trace() CallStack {
|
||||
var pcs [512]uintptr
|
||||
n := runtime.Callers(2, pcs[:])
|
||||
cs := make([]Call, n)
|
||||
|
||||
for i, pc := range pcs[:n] {
|
||||
pcFix := pc
|
||||
if i > 0 && cs[i-1].fn != sigpanic {
|
||||
pcFix--
|
||||
}
|
||||
cs[i] = Call{
|
||||
fn: runtime.FuncForPC(pcFix),
|
||||
pc: pcFix,
|
||||
}
|
||||
}
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// TrimBelow returns a slice of the CallStack with all entries below c
|
||||
// removed.
|
||||
func (cs CallStack) TrimBelow(c Call) CallStack {
|
||||
for len(cs) > 0 && cs[0].pc != c.pc {
|
||||
cs = cs[1:]
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
// TrimAbove returns a slice of the CallStack with all entries above c
|
||||
// removed.
|
||||
func (cs CallStack) TrimAbove(c Call) CallStack {
|
||||
for len(cs) > 0 && cs[len(cs)-1].pc != c.pc {
|
||||
cs = cs[:len(cs)-1]
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
// pkgIndex returns the index that results in file[index:] being the path of
|
||||
// file relative to the compile time GOPATH, and file[:index] being the
|
||||
// $GOPATH/src/ portion of file. funcName must be the name of a function in
|
||||
// file as returned by runtime.Func.Name.
|
||||
func pkgIndex(file, funcName string) int {
|
||||
// As of Go 1.6.2 there is no direct way to know the compile time GOPATH
|
||||
// at runtime, but we can infer the number of path segments in the GOPATH.
|
||||
// We note that runtime.Func.Name() returns the function name qualified by
|
||||
// the import path, which does not include the GOPATH. Thus we can trim
|
||||
// segments from the beginning of the file path until the number of path
|
||||
// separators remaining is one more than the number of path separators in
|
||||
// the function name. For example, given:
|
||||
//
|
||||
// GOPATH /home/user
|
||||
// file /home/user/src/pkg/sub/file.go
|
||||
// fn.Name() pkg/sub.Type.Method
|
||||
//
|
||||
// We want to produce:
|
||||
//
|
||||
// file[:idx] == /home/user/src/
|
||||
// file[idx:] == pkg/sub/file.go
|
||||
//
|
||||
// From this we can easily see that fn.Name() has one less path separator
|
||||
// than our desired result for file[idx:]. We count separators from the
|
||||
// end of the file path until it finds two more than in the function name
|
||||
// and then move one character forward to preserve the initial path
|
||||
// segment without a leading separator.
|
||||
const sep = "/"
|
||||
i := len(file)
|
||||
for n := strings.Count(funcName, sep) + 2; n > 0; n-- {
|
||||
i = strings.LastIndex(file[:i], sep)
|
||||
if i == -1 {
|
||||
i = -len(sep)
|
||||
break
|
||||
}
|
||||
}
|
||||
// get back to 0 or trim the leading separator
|
||||
return i + len(sep)
|
||||
}
|
||||
|
||||
var runtimePath string
|
||||
|
||||
func init() {
|
||||
var pcs [1]uintptr
|
||||
runtime.Callers(0, pcs[:])
|
||||
fn := runtime.FuncForPC(pcs[0])
|
||||
file, _ := fn.FileLine(pcs[0])
|
||||
|
||||
idx := pkgIndex(file, fn.Name())
|
||||
|
||||
runtimePath = file[:idx]
|
||||
if runtime.GOOS == "windows" {
|
||||
runtimePath = strings.ToLower(runtimePath)
|
||||
}
|
||||
}
|
||||
|
||||
func inGoroot(c Call) bool {
|
||||
file := c.file()
|
||||
if len(file) == 0 || file[0] == '?' {
|
||||
return true
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
file = strings.ToLower(file)
|
||||
}
|
||||
return strings.HasPrefix(file, runtimePath) || strings.HasSuffix(file, "/_testmain.go")
|
||||
}
|
||||
|
||||
// TrimRuntime returns a slice of the CallStack with the topmost entries from
|
||||
// the go runtime removed. It considers any calls originating from unknown
|
||||
// files, files under GOROOT, or _testmain.go as part of the runtime.
|
||||
func (cs CallStack) TrimRuntime() CallStack {
|
||||
for len(cs) > 0 && inGoroot(cs[len(cs)-1]) {
|
||||
cs = cs[:len(cs)-1]
|
||||
}
|
||||
return cs
|
||||
}
|
||||
10
Godeps/_workspace/src/github.com/inconshreveable/log15/.travis.yml
generated
vendored
Normal file
10
Godeps/_workspace/src/github.com/inconshreveable/log15/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
11
Godeps/_workspace/src/github.com/inconshreveable/log15/CONTRIBUTORS
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/inconshreveable/log15/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Contributors to log15:
|
||||
|
||||
- Aaron L
|
||||
- Alan Shreve
|
||||
- Chris Hines
|
||||
- Ciaran Downey
|
||||
- Dmitry Chestnykh
|
||||
- Evan Shaw
|
||||
- Péter Szilágyi
|
||||
- Trevor Gattis
|
||||
- Vincent Vanackere
|
||||
13
Godeps/_workspace/src/github.com/inconshreveable/log15/LICENSE
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/inconshreveable/log15/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright 2014 Alan Shreve
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
70
Godeps/_workspace/src/github.com/inconshreveable/log15/README.md
generated
vendored
Normal file
70
Godeps/_workspace/src/github.com/inconshreveable/log15/README.md
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||

|
||||
|
||||
# log15 [](https://godoc.org/github.com/inconshreveable/log15) [](https://travis-ci.org/inconshreveable/log15)
|
||||
|
||||
Package log15 provides an opinionated, simple toolkit for best-practice logging in Go (golang) that is both human and machine readable. It is modeled after the Go standard library's [`io`](http://golang.org/pkg/io/) and [`net/http`](http://golang.org/pkg/net/http/) packages and is an alternative to the standard library's [`log`](http://golang.org/pkg/log/) package.
|
||||
|
||||
## Features
|
||||
- A simple, easy-to-understand API
|
||||
- Promotes structured logging by encouraging use of key/value pairs
|
||||
- Child loggers which inherit and add their own private context
|
||||
- Lazy evaluation of expensive operations
|
||||
- Simple Handler interface allowing for construction of flexible, custom logging configurations with a tiny API.
|
||||
- Color terminal support
|
||||
- Built-in support for logging to files, streams, syslog, and the network
|
||||
- Support for forking records to multiple handlers, buffering records for output, failing over from failed handler writes, + more
|
||||
|
||||
## Versioning
|
||||
The API of the master branch of log15 should always be considered unstable. If you want to rely on a stable API,
|
||||
you must vendor the library.
|
||||
|
||||
## Importing
|
||||
|
||||
```go
|
||||
import log "github.com/inconshreveable/log15"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
// all loggers can have key/value context
|
||||
srvlog := log.New("module", "app/server")
|
||||
|
||||
// all log messages can have key/value context
|
||||
srvlog.Warn("abnormal conn rate", "rate", curRate, "low", lowRate, "high", highRate)
|
||||
|
||||
// child loggers with inherited context
|
||||
connlog := srvlog.New("raddr", c.RemoteAddr())
|
||||
connlog.Info("connection open")
|
||||
|
||||
// lazy evaluation
|
||||
connlog.Debug("ping remote", "latency", log.Lazy{pingRemote})
|
||||
|
||||
// flexible configuration
|
||||
srvlog.SetHandler(log.MultiHandler(
|
||||
log.StreamHandler(os.Stderr, log.LogfmtFormat()),
|
||||
log.LvlFilterHandler(
|
||||
log.LvlError,
|
||||
log.Must.FileHandler("errors.json", log.JsonFormat())))
|
||||
```
|
||||
|
||||
## Breaking API Changes
|
||||
The following commits broke API stability. This reference is intended to help you understand the consequences of updating to a newer version
|
||||
of log15.
|
||||
|
||||
- 57a084d014d4150152b19e4e531399a7145d1540 - Added a `Get()` method to the `Logger` interface to retrieve the current handler
|
||||
- 93404652ee366648fa622b64d1e2b67d75a3094a - `Record` field `Call` changed to `stack.Call` with switch to `github.com/go-stack/stack`
|
||||
- a5e7613673c73281f58e15a87d2cf0cf111e8152 - Restored `syslog.Priority` argument to the `SyslogXxx` handler constructors
|
||||
|
||||
## FAQ
|
||||
|
||||
### The varargs style is brittle and error prone! Can I have type safety please?
|
||||
Yes. Use `log.Ctx`:
|
||||
|
||||
```go
|
||||
srvlog := log.New(log.Ctx{"module": "app/server"})
|
||||
srvlog.Warn("abnormal conn rate", log.Ctx{"rate": curRate, "low": lowRate, "high": highRate})
|
||||
```
|
||||
|
||||
## License
|
||||
Apache
|
||||
333
Godeps/_workspace/src/github.com/inconshreveable/log15/doc.go
generated
vendored
Normal file
333
Godeps/_workspace/src/github.com/inconshreveable/log15/doc.go
generated
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
Package log15 provides an opinionated, simple toolkit for best-practice logging that is
|
||||
both human and machine readable. It is modeled after the standard library's io and net/http
|
||||
packages.
|
||||
|
||||
This package enforces you to only log key/value pairs. Keys must be strings. Values may be
|
||||
any type that you like. The default output format is logfmt, but you may also choose to use
|
||||
JSON instead if that suits you. Here's how you log:
|
||||
|
||||
log.Info("page accessed", "path", r.URL.Path, "user_id", user.id)
|
||||
|
||||
This will output a line that looks like:
|
||||
|
||||
lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9
|
||||
|
||||
Getting Started
|
||||
|
||||
To get started, you'll want to import the library:
|
||||
|
||||
import log "github.com/inconshreveable/log15"
|
||||
|
||||
|
||||
Now you're ready to start logging:
|
||||
|
||||
func main() {
|
||||
log.Info("Program starting", "args", os.Args())
|
||||
}
|
||||
|
||||
|
||||
Convention
|
||||
|
||||
Because recording a human-meaningful message is common and good practice, the first argument to every
|
||||
logging method is the value to the *implicit* key 'msg'.
|
||||
|
||||
Additionally, the level you choose for a message will be automatically added with the key 'lvl', and so
|
||||
will the current timestamp with key 't'.
|
||||
|
||||
You may supply any additional context as a set of key/value pairs to the logging function. log15 allows
|
||||
you to favor terseness, ordering, and speed over safety. This is a reasonable tradeoff for
|
||||
logging functions. You don't need to explicitly state keys/values, log15 understands that they alternate
|
||||
in the variadic argument list:
|
||||
|
||||
log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val)
|
||||
|
||||
If you really do favor your type-safety, you may choose to pass a log.Ctx instead:
|
||||
|
||||
log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val})
|
||||
|
||||
|
||||
Context loggers
|
||||
|
||||
Frequently, you want to add context to a logger so that you can track actions associated with it. An http
|
||||
request is a good example. You can easily create new loggers that have context that is automatically included
|
||||
with each log line:
|
||||
|
||||
requestlogger := log.New("path", r.URL.Path)
|
||||
|
||||
// later
|
||||
requestlogger.Debug("db txn commit", "duration", txnTimer.Finish())
|
||||
|
||||
This will output a log line that includes the path context that is attached to the logger:
|
||||
|
||||
lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12
|
||||
|
||||
|
||||
Handlers
|
||||
|
||||
The Handler interface defines where log lines are printed to and how they are formated. Handler is a
|
||||
single interface that is inspired by net/http's handler interface:
|
||||
|
||||
type Handler interface {
|
||||
Log(r *Record) error
|
||||
}
|
||||
|
||||
|
||||
Handlers can filter records, format them, or dispatch to multiple other Handlers.
|
||||
This package implements a number of Handlers for common logging patterns that are
|
||||
easily composed to create flexible, custom logging structures.
|
||||
|
||||
Here's an example handler that prints logfmt output to Stdout:
|
||||
|
||||
handler := log.StreamHandler(os.Stdout, log.LogfmtFormat())
|
||||
|
||||
Here's an example handler that defers to two other handlers. One handler only prints records
|
||||
from the rpc package in logfmt to standard out. The other prints records at Error level
|
||||
or above in JSON formatted output to the file /var/log/service.json
|
||||
|
||||
handler := log.MultiHandler(
|
||||
log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JsonFormat())),
|
||||
log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler())
|
||||
)
|
||||
|
||||
Logging File Names and Line Numbers
|
||||
|
||||
This package implements three Handlers that add debugging information to the
|
||||
context, CallerFileHandler, CallerFuncHandler and CallerStackHandler. Here's
|
||||
an example that adds the source file and line number of each logging call to
|
||||
the context.
|
||||
|
||||
h := log.CallerFileHandler(log.StdoutHandler())
|
||||
log.Root().SetHandler(h)
|
||||
...
|
||||
log.Error("open file", "err", err)
|
||||
|
||||
This will output a line that looks like:
|
||||
|
||||
lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" caller=data.go:42
|
||||
|
||||
Here's an example that logs the call stack rather than just the call site.
|
||||
|
||||
h := log.CallerStackHandler("%+v", log.StdoutHandler())
|
||||
log.Root().SetHandler(h)
|
||||
...
|
||||
log.Error("open file", "err", err)
|
||||
|
||||
This will output a line that looks like:
|
||||
|
||||
lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" stack="[pkg/data.go:42 pkg/cmd/main.go]"
|
||||
|
||||
The "%+v" format instructs the handler to include the path of the source file
|
||||
relative to the compile time GOPATH. The github.com/go-stack/stack package
|
||||
documents the full list of formatting verbs and modifiers available.
|
||||
|
||||
Custom Handlers
|
||||
|
||||
The Handler interface is so simple that it's also trivial to write your own. Let's create an
|
||||
example handler which tries to write to one handler, but if that fails it falls back to
|
||||
writing to another handler and includes the error that it encountered when trying to write
|
||||
to the primary. This might be useful when trying to log over a network socket, but if that
|
||||
fails you want to log those records to a file on disk.
|
||||
|
||||
type BackupHandler struct {
|
||||
Primary Handler
|
||||
Secondary Handler
|
||||
}
|
||||
|
||||
func (h *BackupHandler) Log (r *Record) error {
|
||||
err := h.Primary.Log(r)
|
||||
if err != nil {
|
||||
r.Ctx = append(ctx, "primary_err", err)
|
||||
return h.Secondary.Log(r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
This pattern is so useful that a generic version that handles an arbitrary number of Handlers
|
||||
is included as part of this library called FailoverHandler.
|
||||
|
||||
Logging Expensive Operations
|
||||
|
||||
Sometimes, you want to log values that are extremely expensive to compute, but you don't want to pay
|
||||
the price of computing them if you haven't turned up your logging level to a high level of detail.
|
||||
|
||||
This package provides a simple type to annotate a logging operation that you want to be evaluated
|
||||
lazily, just when it is about to be logged, so that it would not be evaluated if an upstream Handler
|
||||
filters it out. Just wrap any function which takes no arguments with the log.Lazy type. For example:
|
||||
|
||||
func factorRSAKey() (factors []int) {
|
||||
// return the factors of a very large number
|
||||
}
|
||||
|
||||
log.Debug("factors", log.Lazy{factorRSAKey})
|
||||
|
||||
If this message is not logged for any reason (like logging at the Error level), then
|
||||
factorRSAKey is never evaluated.
|
||||
|
||||
Dynamic context values
|
||||
|
||||
The same log.Lazy mechanism can be used to attach context to a logger which you want to be
|
||||
evaluated when the message is logged, but not when the logger is created. For example, let's imagine
|
||||
a game where you have Player objects:
|
||||
|
||||
type Player struct {
|
||||
name string
|
||||
alive bool
|
||||
log.Logger
|
||||
}
|
||||
|
||||
You always want to log a player's name and whether they're alive or dead, so when you create the player
|
||||
object, you might do:
|
||||
|
||||
p := &Player{name: name, alive: true}
|
||||
p.Logger = log.New("name", p.name, "alive", p.alive)
|
||||
|
||||
Only now, even after a player has died, the logger will still report they are alive because the logging
|
||||
context is evaluated when the logger was created. By using the Lazy wrapper, we can defer the evaluation
|
||||
of whether the player is alive or not to each log message, so that the log records will reflect the player's
|
||||
current state no matter when the log message is written:
|
||||
|
||||
p := &Player{name: name, alive: true}
|
||||
isAlive := func() bool { return p.alive }
|
||||
player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive})
|
||||
|
||||
Terminal Format
|
||||
|
||||
If log15 detects that stdout is a terminal, it will configure the default
|
||||
handler for it (which is log.StdoutHandler) to use TerminalFormat. This format
|
||||
logs records nicely for your terminal, including color-coded output based
|
||||
on log level.
|
||||
|
||||
Error Handling
|
||||
|
||||
Becasuse log15 allows you to step around the type system, there are a few ways you can specify
|
||||
invalid arguments to the logging functions. You could, for example, wrap something that is not
|
||||
a zero-argument function with log.Lazy or pass a context key that is not a string. Since logging libraries
|
||||
are typically the mechanism by which errors are reported, it would be onerous for the logging functions
|
||||
to return errors. Instead, log15 handles errors by making these guarantees to you:
|
||||
|
||||
- Any log record containing an error will still be printed with the error explained to you as part of the log record.
|
||||
|
||||
- Any log record containing an error will include the context key LOG15_ERROR, enabling you to easily
|
||||
(and if you like, automatically) detect if any of your logging calls are passing bad values.
|
||||
|
||||
Understanding this, you might wonder why the Handler interface can return an error value in its Log method. Handlers
|
||||
are encouraged to return errors only if they fail to write their log records out to an external source like if the
|
||||
syslog daemon is not responding. This allows the construction of useful handlers which cope with those failures
|
||||
like the FailoverHandler.
|
||||
|
||||
Library Use
|
||||
|
||||
log15 is intended to be useful for library authors as a way to provide configurable logging to
|
||||
users of their library. Best practice for use in a library is to always disable all output for your logger
|
||||
by default and to provide a public Logger instance that consumers of your library can configure. Like so:
|
||||
|
||||
package yourlib
|
||||
|
||||
import "github.com/inconshreveable/log15"
|
||||
|
||||
var Log = log.New()
|
||||
|
||||
func init() {
|
||||
Log.SetHandler(log.DiscardHandler())
|
||||
}
|
||||
|
||||
Users of your library may then enable it if they like:
|
||||
|
||||
import "github.com/inconshreveable/log15"
|
||||
import "example.com/yourlib"
|
||||
|
||||
func main() {
|
||||
handler := // custom handler setup
|
||||
yourlib.Log.SetHandler(handler)
|
||||
}
|
||||
|
||||
Best practices attaching logger context
|
||||
|
||||
The ability to attach context to a logger is a powerful one. Where should you do it and why?
|
||||
I favor embedding a Logger directly into any persistent object in my application and adding
|
||||
unique, tracing context keys to it. For instance, imagine I am writing a web browser:
|
||||
|
||||
type Tab struct {
|
||||
url string
|
||||
render *RenderingContext
|
||||
// ...
|
||||
|
||||
Logger
|
||||
}
|
||||
|
||||
func NewTab(url string) *Tab {
|
||||
return &Tab {
|
||||
// ...
|
||||
url: url,
|
||||
|
||||
Logger: log.New("url", url),
|
||||
}
|
||||
}
|
||||
|
||||
When a new tab is created, I assign a logger to it with the url of
|
||||
the tab as context so it can easily be traced through the logs.
|
||||
Now, whenever we perform any operation with the tab, we'll log with its
|
||||
embedded logger and it will include the tab title automatically:
|
||||
|
||||
tab.Debug("moved position", "idx", tab.idx)
|
||||
|
||||
There's only one problem. What if the tab url changes? We could
|
||||
use log.Lazy to make sure the current url is always written, but that
|
||||
would mean that we couldn't trace a tab's full lifetime through our
|
||||
logs after the user navigate to a new URL.
|
||||
|
||||
Instead, think about what values to attach to your loggers the
|
||||
same way you think about what to use as a key in a SQL database schema.
|
||||
If it's possible to use a natural key that is unique for the lifetime of the
|
||||
object, do so. But otherwise, log15's ext package has a handy RandId
|
||||
function to let you generate what you might call "surrogate keys"
|
||||
They're just random hex identifiers to use for tracing. Back to our
|
||||
Tab example, we would prefer to set up our Logger like so:
|
||||
|
||||
import logext "github.com/inconshreveable/log15/ext"
|
||||
|
||||
t := &Tab {
|
||||
// ...
|
||||
url: url,
|
||||
}
|
||||
|
||||
t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl})
|
||||
return t
|
||||
|
||||
Now we'll have a unique traceable identifier even across loading new urls, but
|
||||
we'll still be able to see the tab's current url in the log messages.
|
||||
|
||||
Must
|
||||
|
||||
For all Handler functions which can return an error, there is a version of that
|
||||
function which will return no error but panics on failure. They are all available
|
||||
on the Must object. For example:
|
||||
|
||||
log.Must.FileHandler("/path", log.JsonFormat)
|
||||
log.Must.NetHandler("tcp", ":1234", log.JsonFormat)
|
||||
|
||||
Inspiration and Credit
|
||||
|
||||
All of the following excellent projects inspired the design of this library:
|
||||
|
||||
code.google.com/p/log4go
|
||||
|
||||
github.com/op/go-logging
|
||||
|
||||
github.com/technoweenie/grohl
|
||||
|
||||
github.com/Sirupsen/logrus
|
||||
|
||||
github.com/kr/logfmt
|
||||
|
||||
github.com/spacemonkeygo/spacelog
|
||||
|
||||
golang's stdlib, notably io and net/http
|
||||
|
||||
The Name
|
||||
|
||||
https://xkcd.com/927/
|
||||
|
||||
*/
|
||||
package log15
|
||||
257
Godeps/_workspace/src/github.com/inconshreveable/log15/format.go
generated
vendored
Normal file
257
Godeps/_workspace/src/github.com/inconshreveable/log15/format.go
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
package log15
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
timeFormat = "2006-01-02T15:04:05-0700"
|
||||
termTimeFormat = "01-02|15:04:05"
|
||||
floatFormat = 'f'
|
||||
termMsgJust = 40
|
||||
)
|
||||
|
||||
type Format interface {
|
||||
Format(r *Record) []byte
|
||||
}
|
||||
|
||||
// FormatFunc returns a new Format object which uses
|
||||
// the given function to perform record formatting.
|
||||
func FormatFunc(f func(*Record) []byte) Format {
|
||||
return formatFunc(f)
|
||||
}
|
||||
|
||||
type formatFunc func(*Record) []byte
|
||||
|
||||
func (f formatFunc) Format(r *Record) []byte {
|
||||
return f(r)
|
||||
}
|
||||
|
||||
// TerminalFormat formats log records optimized for human readability on
|
||||
// a terminal with color-coded level output and terser human friendly timestamp.
|
||||
// This format should only be used for interactive programs or while developing.
|
||||
//
|
||||
// [TIME] [LEVEL] MESAGE key=value key=value ...
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// [May 16 20:58:45] [DBUG] remove route ns=haproxy addr=127.0.0.1:50002
|
||||
//
|
||||
func TerminalFormat() Format {
|
||||
return FormatFunc(func(r *Record) []byte {
|
||||
var color = 0
|
||||
switch r.Lvl {
|
||||
case LvlCrit:
|
||||
color = 35
|
||||
case LvlError:
|
||||
color = 31
|
||||
case LvlWarn:
|
||||
color = 33
|
||||
case LvlInfo:
|
||||
color = 32
|
||||
case LvlDebug:
|
||||
color = 36
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
lvl := strings.ToUpper(r.Lvl.String())
|
||||
if color > 0 {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), r.Msg)
|
||||
} else {
|
||||
fmt.Fprintf(b, "[%s] [%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg)
|
||||
}
|
||||
|
||||
// try to justify the log output for short messages
|
||||
if len(r.Ctx) > 0 && len(r.Msg) < termMsgJust {
|
||||
b.Write(bytes.Repeat([]byte{' '}, termMsgJust-len(r.Msg)))
|
||||
}
|
||||
|
||||
// print the keys logfmt style
|
||||
logfmt(b, r.Ctx, color)
|
||||
return b.Bytes()
|
||||
})
|
||||
}
|
||||
|
||||
// LogfmtFormat prints records in logfmt format, an easy machine-parseable but human-readable
|
||||
// format for key/value pairs.
|
||||
//
|
||||
// For more details see: http://godoc.org/github.com/kr/logfmt
|
||||
//
|
||||
func LogfmtFormat() Format {
|
||||
return FormatFunc(func(r *Record) []byte {
|
||||
common := []interface{}{r.KeyNames.Time, r.Time, r.KeyNames.Lvl, r.Lvl, r.KeyNames.Msg, r.Msg}
|
||||
buf := &bytes.Buffer{}
|
||||
logfmt(buf, append(common, r.Ctx...), 0)
|
||||
return buf.Bytes()
|
||||
})
|
||||
}
|
||||
|
||||
func logfmt(buf *bytes.Buffer, ctx []interface{}, color int) {
|
||||
for i := 0; i < len(ctx); i += 2 {
|
||||
if i != 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
|
||||
k, ok := ctx[i].(string)
|
||||
v := formatLogfmtValue(ctx[i+1])
|
||||
if !ok {
|
||||
k, v = errorKey, formatLogfmtValue(k)
|
||||
}
|
||||
|
||||
// XXX: we should probably check that all of your key bytes aren't invalid
|
||||
if color > 0 {
|
||||
fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=%s", color, k, v)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%s=%s", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
|
||||
// JsonFormat formats log records as JSON objects separated by newlines.
|
||||
// It is the equivalent of JsonFormatEx(false, true).
|
||||
func JsonFormat() Format {
|
||||
return JsonFormatEx(false, true)
|
||||
}
|
||||
|
||||
// JsonFormatEx formats log records as JSON objects. If pretty is true,
|
||||
// records will be pretty-printed. If lineSeparated is true, records
|
||||
// will be logged with a new line between each record.
|
||||
func JsonFormatEx(pretty, lineSeparated bool) Format {
|
||||
jsonMarshal := json.Marshal
|
||||
if pretty {
|
||||
jsonMarshal = func(v interface{}) ([]byte, error) {
|
||||
return json.MarshalIndent(v, "", " ")
|
||||
}
|
||||
}
|
||||
|
||||
return FormatFunc(func(r *Record) []byte {
|
||||
props := make(map[string]interface{})
|
||||
|
||||
props[r.KeyNames.Time] = r.Time
|
||||
props[r.KeyNames.Lvl] = r.Lvl.String()
|
||||
props[r.KeyNames.Msg] = r.Msg
|
||||
|
||||
for i := 0; i < len(r.Ctx); i += 2 {
|
||||
k, ok := r.Ctx[i].(string)
|
||||
if !ok {
|
||||
props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i])
|
||||
}
|
||||
props[k] = formatJsonValue(r.Ctx[i+1])
|
||||
}
|
||||
|
||||
b, err := jsonMarshal(props)
|
||||
if err != nil {
|
||||
b, _ = jsonMarshal(map[string]string{
|
||||
errorKey: err.Error(),
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
if lineSeparated {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
|
||||
return b
|
||||
})
|
||||
}
|
||||
|
||||
func formatShared(value interface{}) (result interface{}) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
result = "nil"
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
switch v := value.(type) {
|
||||
case time.Time:
|
||||
return v.Format(timeFormat)
|
||||
|
||||
case error:
|
||||
return v.Error()
|
||||
|
||||
case fmt.Stringer:
|
||||
return v.String()
|
||||
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func formatJsonValue(value interface{}) interface{} {
|
||||
value = formatShared(value)
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64, float32, float64, uint, uint8, uint16, uint32, uint64, string:
|
||||
return value
|
||||
default:
|
||||
return fmt.Sprintf("%+v", value)
|
||||
}
|
||||
}
|
||||
|
||||
// formatValue formats a value for serialization
|
||||
func formatLogfmtValue(value interface{}) string {
|
||||
if value == nil {
|
||||
return "nil"
|
||||
}
|
||||
|
||||
value = formatShared(value)
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
return strconv.FormatBool(v)
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
|
||||
case float64:
|
||||
return strconv.FormatFloat(v, floatFormat, 3, 64)
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
return fmt.Sprintf("%d", value)
|
||||
case string:
|
||||
return escapeString(v)
|
||||
default:
|
||||
return escapeString(fmt.Sprintf("%+v", value))
|
||||
}
|
||||
}
|
||||
|
||||
func escapeString(s string) string {
|
||||
needQuotes := false
|
||||
e := bytes.Buffer{}
|
||||
e.WriteByte('"')
|
||||
for _, r := range s {
|
||||
if r <= ' ' || r == '=' || r == '"' {
|
||||
needQuotes = true
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '\\', '"':
|
||||
e.WriteByte('\\')
|
||||
e.WriteByte(byte(r))
|
||||
case '\n':
|
||||
e.WriteByte('\\')
|
||||
e.WriteByte('n')
|
||||
case '\r':
|
||||
e.WriteByte('\\')
|
||||
e.WriteByte('r')
|
||||
case '\t':
|
||||
e.WriteByte('\\')
|
||||
e.WriteByte('t')
|
||||
default:
|
||||
e.WriteRune(r)
|
||||
}
|
||||
}
|
||||
e.WriteByte('"')
|
||||
start, stop := 0, e.Len()
|
||||
if !needQuotes {
|
||||
start, stop = 1, stop-1
|
||||
}
|
||||
return string(e.Bytes()[start:stop])
|
||||
}
|
||||
356
Godeps/_workspace/src/github.com/inconshreveable/log15/handler.go
generated
vendored
Normal file
356
Godeps/_workspace/src/github.com/inconshreveable/log15/handler.go
generated
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
package log15
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/go-stack/stack"
|
||||
)
|
||||
|
||||
// A Logger prints its log records by writing to a Handler.
|
||||
// The Handler interface defines where and how log records are written.
|
||||
// Handlers are composable, providing you great flexibility in combining
|
||||
// them to achieve the logging structure that suits your applications.
|
||||
type Handler interface {
|
||||
Log(r *Record) error
|
||||
}
|
||||
|
||||
// FuncHandler returns a Handler that logs records with the given
|
||||
// function.
|
||||
func FuncHandler(fn func(r *Record) error) Handler {
|
||||
return funcHandler(fn)
|
||||
}
|
||||
|
||||
type funcHandler func(r *Record) error
|
||||
|
||||
func (h funcHandler) Log(r *Record) error {
|
||||
return h(r)
|
||||
}
|
||||
|
||||
// StreamHandler writes log records to an io.Writer
|
||||
// with the given format. StreamHandler can be used
|
||||
// to easily begin writing log records to other
|
||||
// outputs.
|
||||
//
|
||||
// StreamHandler wraps itself with LazyHandler and SyncHandler
|
||||
// to evaluate Lazy objects and perform safe concurrent writes.
|
||||
func StreamHandler(wr io.Writer, fmtr Format) Handler {
|
||||
h := FuncHandler(func(r *Record) error {
|
||||
_, err := wr.Write(fmtr.Format(r))
|
||||
return err
|
||||
})
|
||||
return LazyHandler(SyncHandler(h))
|
||||
}
|
||||
|
||||
// SyncHandler can be wrapped around a handler to guarantee that
|
||||
// only a single Log operation can proceed at a time. It's necessary
|
||||
// for thread-safe concurrent writes.
|
||||
func SyncHandler(h Handler) Handler {
|
||||
var mu sync.Mutex
|
||||
return FuncHandler(func(r *Record) error {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
return h.Log(r)
|
||||
})
|
||||
}
|
||||
|
||||
// FileHandler returns a handler which writes log records to the give file
|
||||
// using the given format. If the path
|
||||
// already exists, FileHandler will append to the given file. If it does not,
|
||||
// FileHandler will create the file with mode 0644.
|
||||
func FileHandler(path string, fmtr Format) (Handler, error) {
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return closingHandler{f, StreamHandler(f, fmtr)}, nil
|
||||
}
|
||||
|
||||
// NetHandler opens a socket to the given address and writes records
|
||||
// over the connection.
|
||||
func NetHandler(network, addr string, fmtr Format) (Handler, error) {
|
||||
conn, err := net.Dial(network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
|
||||
}
|
||||
|
||||
// XXX: closingHandler is essentially unused at the moment
|
||||
// it's meant for a future time when the Handler interface supports
|
||||
// a possible Close() operation
|
||||
type closingHandler struct {
|
||||
io.WriteCloser
|
||||
Handler
|
||||
}
|
||||
|
||||
func (h *closingHandler) Close() error {
|
||||
return h.WriteCloser.Close()
|
||||
}
|
||||
|
||||
// CallerFileHandler returns a Handler that adds the line number and file of
|
||||
// the calling function to the context with key "caller".
|
||||
func CallerFileHandler(h Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call))
|
||||
return h.Log(r)
|
||||
})
|
||||
}
|
||||
|
||||
// CallerFuncHandler returns a Handler that adds the calling function name to
|
||||
// the context with key "fn".
|
||||
func CallerFuncHandler(h Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
r.Ctx = append(r.Ctx, "fn", fmt.Sprintf("%+n", r.Call))
|
||||
return h.Log(r)
|
||||
})
|
||||
}
|
||||
|
||||
// CallerStackHandler returns a Handler that adds a stack trace to the context
|
||||
// with key "stack". The stack trace is formated as a space separated list of
|
||||
// call sites inside matching []'s. The most recent call site is listed first.
|
||||
// Each call site is formatted according to format. See the documentation of
|
||||
// package github.com/go-stack/stack for the list of supported formats.
|
||||
func CallerStackHandler(format string, h Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
s := stack.Trace().TrimBelow(r.Call).TrimRuntime()
|
||||
if len(s) > 0 {
|
||||
r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s))
|
||||
}
|
||||
return h.Log(r)
|
||||
})
|
||||
}
|
||||
|
||||
// FilterHandler returns a Handler that only writes records to the
|
||||
// wrapped Handler if the given function evaluates true. For example,
|
||||
// to only log records where the 'err' key is not nil:
|
||||
//
|
||||
// logger.SetHandler(FilterHandler(func(r *Record) bool {
|
||||
// for i := 0; i < len(r.Ctx); i += 2 {
|
||||
// if r.Ctx[i] == "err" {
|
||||
// return r.Ctx[i+1] != nil
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
// }, h))
|
||||
//
|
||||
func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
if fn(r) {
|
||||
return h.Log(r)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// MatchFilterHandler returns a Handler that only writes records
|
||||
// to the wrapped Handler if the given key in the logged
|
||||
// context matches the value. For example, to only log records
|
||||
// from your ui package:
|
||||
//
|
||||
// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
|
||||
//
|
||||
func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
|
||||
return FilterHandler(func(r *Record) (pass bool) {
|
||||
switch key {
|
||||
case r.KeyNames.Lvl:
|
||||
return r.Lvl == value
|
||||
case r.KeyNames.Time:
|
||||
return r.Time == value
|
||||
case r.KeyNames.Msg:
|
||||
return r.Msg == value
|
||||
}
|
||||
|
||||
for i := 0; i < len(r.Ctx); i += 2 {
|
||||
if r.Ctx[i] == key {
|
||||
return r.Ctx[i+1] == value
|
||||
}
|
||||
}
|
||||
return false
|
||||
}, h)
|
||||
}
|
||||
|
||||
// LvlFilterHandler returns a Handler that only writes
|
||||
// records which are less than the given verbosity
|
||||
// level to the wrapped Handler. For example, to only
|
||||
// log Error/Crit records:
|
||||
//
|
||||
// log.LvlFilterHandler(log.Error, log.StdoutHandler)
|
||||
//
|
||||
func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
|
||||
return FilterHandler(func(r *Record) (pass bool) {
|
||||
return r.Lvl <= maxLvl
|
||||
}, h)
|
||||
}
|
||||
|
||||
// A MultiHandler dispatches any write to each of its handlers.
|
||||
// This is useful for writing different types of log information
|
||||
// to different locations. For example, to log to a file and
|
||||
// standard error:
|
||||
//
|
||||
// log.MultiHandler(
|
||||
// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
|
||||
// log.StderrHandler)
|
||||
//
|
||||
func MultiHandler(hs ...Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
for _, h := range hs {
|
||||
// what to do about failures?
|
||||
h.Log(r)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// A FailoverHandler writes all log records to the first handler
|
||||
// specified, but will failover and write to the second handler if
|
||||
// the first handler has failed, and so on for all handlers specified.
|
||||
// For example you might want to log to a network socket, but failover
|
||||
// to writing to a file if the network fails, and then to
|
||||
// standard out if the file write fails:
|
||||
//
|
||||
// log.FailoverHandler(
|
||||
// log.Must.NetHandler("tcp", ":9090", log.JsonFormat()),
|
||||
// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
|
||||
// log.StdoutHandler)
|
||||
//
|
||||
// All writes that do not go to the first handler will add context with keys of
|
||||
// the form "failover_err_{idx}" which explain the error encountered while
|
||||
// trying to write to the handlers before them in the list.
|
||||
func FailoverHandler(hs ...Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
var err error
|
||||
for i, h := range hs {
|
||||
err = h.Log(r)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else {
|
||||
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// ChannelHandler writes all records to the given channel.
|
||||
// It blocks if the channel is full. Useful for async processing
|
||||
// of log messages, it's used by BufferedHandler.
|
||||
func ChannelHandler(recs chan<- *Record) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
recs <- r
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// BufferedHandler writes all records to a buffered
|
||||
// channel of the given size which flushes into the wrapped
|
||||
// handler whenever it is available for writing. Since these
|
||||
// writes happen asynchronously, all writes to a BufferedHandler
|
||||
// never return an error and any errors from the wrapped handler are ignored.
|
||||
func BufferedHandler(bufSize int, h Handler) Handler {
|
||||
recs := make(chan *Record, bufSize)
|
||||
go func() {
|
||||
for m := range recs {
|
||||
_ = h.Log(m)
|
||||
}
|
||||
}()
|
||||
return ChannelHandler(recs)
|
||||
}
|
||||
|
||||
// LazyHandler writes all values to the wrapped handler after evaluating
|
||||
// any lazy functions in the record's context. It is already wrapped
|
||||
// around StreamHandler and SyslogHandler in this library, you'll only need
|
||||
// it if you write your own Handler.
|
||||
func LazyHandler(h Handler) Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
// go through the values (odd indices) and reassign
|
||||
// the values of any lazy fn to the result of its execution
|
||||
hadErr := false
|
||||
for i := 1; i < len(r.Ctx); i += 2 {
|
||||
lz, ok := r.Ctx[i].(Lazy)
|
||||
if ok {
|
||||
v, err := evaluateLazy(lz)
|
||||
if err != nil {
|
||||
hadErr = true
|
||||
r.Ctx[i] = err
|
||||
} else {
|
||||
if cs, ok := v.(stack.CallStack); ok {
|
||||
v = cs.TrimBelow(r.Call).TrimRuntime()
|
||||
}
|
||||
r.Ctx[i] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hadErr {
|
||||
r.Ctx = append(r.Ctx, errorKey, "bad lazy")
|
||||
}
|
||||
|
||||
return h.Log(r)
|
||||
})
|
||||
}
|
||||
|
||||
func evaluateLazy(lz Lazy) (interface{}, error) {
|
||||
t := reflect.TypeOf(lz.Fn)
|
||||
|
||||
if t.Kind() != reflect.Func {
|
||||
return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
|
||||
}
|
||||
|
||||
if t.NumIn() > 0 {
|
||||
return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
|
||||
}
|
||||
|
||||
if t.NumOut() == 0 {
|
||||
return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(lz.Fn)
|
||||
results := value.Call([]reflect.Value{})
|
||||
if len(results) == 1 {
|
||||
return results[0].Interface(), nil
|
||||
} else {
|
||||
values := make([]interface{}, len(results))
|
||||
for i, v := range results {
|
||||
values[i] = v.Interface()
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
}
|
||||
|
||||
// DiscardHandler reports success for all writes but does nothing.
|
||||
// It is useful for dynamically disabling logging at runtime via
|
||||
// a Logger's SetHandler method.
|
||||
func DiscardHandler() Handler {
|
||||
return FuncHandler(func(r *Record) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// The Must object provides the following Handler creation functions
|
||||
// which instead of returning an error parameter only return a Handler
|
||||
// and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
|
||||
var Must muster
|
||||
|
||||
func must(h Handler, err error) Handler {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
type muster struct{}
|
||||
|
||||
func (m muster) FileHandler(path string, fmtr Format) Handler {
|
||||
return must(FileHandler(path, fmtr))
|
||||
}
|
||||
|
||||
func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
|
||||
return must(NetHandler(network, addr, fmtr))
|
||||
}
|
||||
26
Godeps/_workspace/src/github.com/inconshreveable/log15/handler_go13.go
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/inconshreveable/log15/handler_go13.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// +build !go1.4
|
||||
|
||||
package log15
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// swapHandler wraps another handler that may be swapped out
|
||||
// dynamically at runtime in a thread-safe fashion.
|
||||
type swapHandler struct {
|
||||
handler unsafe.Pointer
|
||||
}
|
||||
|
||||
func (h *swapHandler) Log(r *Record) error {
|
||||
return h.Get().Log(r)
|
||||
}
|
||||
|
||||
func (h *swapHandler) Get() Handler {
|
||||
return *(*Handler)(atomic.LoadPointer(&h.handler))
|
||||
}
|
||||
|
||||
func (h *swapHandler) Swap(newHandler Handler) {
|
||||
atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
|
||||
}
|
||||
23
Godeps/_workspace/src/github.com/inconshreveable/log15/handler_go14.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/inconshreveable/log15/handler_go14.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// +build go1.4
|
||||
|
||||
package log15
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// swapHandler wraps another handler that may be swapped out
|
||||
// dynamically at runtime in a thread-safe fashion.
|
||||
type swapHandler struct {
|
||||
handler atomic.Value
|
||||
}
|
||||
|
||||
func (h *swapHandler) Log(r *Record) error {
|
||||
return (*h.handler.Load().(*Handler)).Log(r)
|
||||
}
|
||||
|
||||
func (h *swapHandler) Swap(newHandler Handler) {
|
||||
h.handler.Store(&newHandler)
|
||||
}
|
||||
|
||||
func (h *swapHandler) Get() Handler {
|
||||
return *h.handler.Load().(*Handler)
|
||||
}
|
||||
208
Godeps/_workspace/src/github.com/inconshreveable/log15/logger.go
generated
vendored
Normal file
208
Godeps/_workspace/src/github.com/inconshreveable/log15/logger.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package log15
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-stack/stack"
|
||||
)
|
||||
|
||||
const timeKey = "t"
|
||||
const lvlKey = "lvl"
|
||||
const msgKey = "msg"
|
||||
const errorKey = "LOG15_ERROR"
|
||||
|
||||
type Lvl int
|
||||
|
||||
const (
|
||||
LvlCrit Lvl = iota
|
||||
LvlError
|
||||
LvlWarn
|
||||
LvlInfo
|
||||
LvlDebug
|
||||
)
|
||||
|
||||
// Returns the name of a Lvl
|
||||
func (l Lvl) String() string {
|
||||
switch l {
|
||||
case LvlDebug:
|
||||
return "dbug"
|
||||
case LvlInfo:
|
||||
return "info"
|
||||
case LvlWarn:
|
||||
return "warn"
|
||||
case LvlError:
|
||||
return "eror"
|
||||
case LvlCrit:
|
||||
return "crit"
|
||||
default:
|
||||
panic("bad level")
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the appropriate Lvl from a string name.
|
||||
// Useful for parsing command line args and configuration files.
|
||||
func LvlFromString(lvlString string) (Lvl, error) {
|
||||
switch lvlString {
|
||||
case "debug", "dbug":
|
||||
return LvlDebug, nil
|
||||
case "info":
|
||||
return LvlInfo, nil
|
||||
case "warn":
|
||||
return LvlWarn, nil
|
||||
case "error", "eror":
|
||||
return LvlError, nil
|
||||
case "crit":
|
||||
return LvlCrit, nil
|
||||
default:
|
||||
return LvlDebug, fmt.Errorf("Unknown level: %v", lvlString)
|
||||
}
|
||||
}
|
||||
|
||||
// A Record is what a Logger asks its handler to write
|
||||
type Record struct {
|
||||
Time time.Time
|
||||
Lvl Lvl
|
||||
Msg string
|
||||
Ctx []interface{}
|
||||
Call stack.Call
|
||||
KeyNames RecordKeyNames
|
||||
}
|
||||
|
||||
type RecordKeyNames struct {
|
||||
Time string
|
||||
Msg string
|
||||
Lvl string
|
||||
}
|
||||
|
||||
// A Logger writes key/value pairs to a Handler
|
||||
type Logger interface {
|
||||
// New returns a new Logger that has this logger's context plus the given context
|
||||
New(ctx ...interface{}) Logger
|
||||
|
||||
// GetHandler gets the handler associated with the logger.
|
||||
GetHandler() Handler
|
||||
|
||||
// SetHandler updates the logger to write records to the specified handler.
|
||||
SetHandler(h Handler)
|
||||
|
||||
// Log a message at the given level with context key/value pairs
|
||||
Debug(msg string, ctx ...interface{})
|
||||
Info(msg string, ctx ...interface{})
|
||||
Warn(msg string, ctx ...interface{})
|
||||
Error(msg string, ctx ...interface{})
|
||||
Crit(msg string, ctx ...interface{})
|
||||
}
|
||||
|
||||
type logger struct {
|
||||
ctx []interface{}
|
||||
h *swapHandler
|
||||
}
|
||||
|
||||
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
|
||||
l.h.Log(&Record{
|
||||
Time: time.Now(),
|
||||
Lvl: lvl,
|
||||
Msg: msg,
|
||||
Ctx: newContext(l.ctx, ctx),
|
||||
Call: stack.Caller(2),
|
||||
KeyNames: RecordKeyNames{
|
||||
Time: timeKey,
|
||||
Msg: msgKey,
|
||||
Lvl: lvlKey,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (l *logger) New(ctx ...interface{}) Logger {
|
||||
child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
|
||||
child.SetHandler(l.h)
|
||||
return child
|
||||
}
|
||||
|
||||
func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
|
||||
normalizedSuffix := normalize(suffix)
|
||||
newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
|
||||
n := copy(newCtx, prefix)
|
||||
copy(newCtx[n:], normalizedSuffix)
|
||||
return newCtx
|
||||
}
|
||||
|
||||
func (l *logger) Debug(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlDebug, ctx)
|
||||
}
|
||||
|
||||
func (l *logger) Info(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlInfo, ctx)
|
||||
}
|
||||
|
||||
func (l *logger) Warn(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlWarn, ctx)
|
||||
}
|
||||
|
||||
func (l *logger) Error(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlError, ctx)
|
||||
}
|
||||
|
||||
func (l *logger) Crit(msg string, ctx ...interface{}) {
|
||||
l.write(msg, LvlCrit, ctx)
|
||||
}
|
||||
|
||||
func (l *logger) GetHandler() Handler {
|
||||
return l.h.Get()
|
||||
}
|
||||
|
||||
func (l *logger) SetHandler(h Handler) {
|
||||
l.h.Swap(h)
|
||||
}
|
||||
|
||||
func normalize(ctx []interface{}) []interface{} {
|
||||
// if the caller passed a Ctx object, then expand it
|
||||
if len(ctx) == 1 {
|
||||
if ctxMap, ok := ctx[0].(Ctx); ok {
|
||||
ctx = ctxMap.toArray()
|
||||
}
|
||||
}
|
||||
|
||||
// ctx needs to be even because it's a series of key/value pairs
|
||||
// no one wants to check for errors on logging functions,
|
||||
// so instead of erroring on bad input, we'll just make sure
|
||||
// that things are the right length and users can fix bugs
|
||||
// when they see the output looks wrong
|
||||
if len(ctx)%2 != 0 {
|
||||
ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Lazy allows you to defer calculation of a logged value that is expensive
|
||||
// to compute until it is certain that it must be evaluated with the given filters.
|
||||
//
|
||||
// Lazy may also be used in conjunction with a Logger's New() function
|
||||
// to generate a child logger which always reports the current value of changing
|
||||
// state.
|
||||
//
|
||||
// You may wrap any function which takes no arguments to Lazy. It may return any
|
||||
// number of values of any type.
|
||||
type Lazy struct {
|
||||
Fn interface{}
|
||||
}
|
||||
|
||||
// Ctx is a map of key/value pairs to pass as context to a log function
|
||||
// Use this only if you really need greater safety around the arguments you pass
|
||||
// to the logging functions.
|
||||
type Ctx map[string]interface{}
|
||||
|
||||
func (c Ctx) toArray() []interface{} {
|
||||
arr := make([]interface{}, len(c)*2)
|
||||
|
||||
i := 0
|
||||
for k, v := range c {
|
||||
arr[i] = k
|
||||
arr[i+1] = v
|
||||
i += 2
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
67
Godeps/_workspace/src/github.com/inconshreveable/log15/root.go
generated
vendored
Normal file
67
Godeps/_workspace/src/github.com/inconshreveable/log15/root.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package log15
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/inconshreveable/log15/term"
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
var (
|
||||
root *logger
|
||||
StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
|
||||
StderrHandler = StreamHandler(os.Stderr, LogfmtFormat())
|
||||
)
|
||||
|
||||
func init() {
|
||||
if term.IsTty(os.Stdout.Fd()) {
|
||||
StdoutHandler = StreamHandler(colorable.NewColorableStdout(), TerminalFormat())
|
||||
}
|
||||
|
||||
if term.IsTty(os.Stderr.Fd()) {
|
||||
StderrHandler = StreamHandler(colorable.NewColorableStderr(), TerminalFormat())
|
||||
}
|
||||
|
||||
root = &logger{[]interface{}{}, new(swapHandler)}
|
||||
root.SetHandler(StdoutHandler)
|
||||
}
|
||||
|
||||
// New returns a new logger with the given context.
|
||||
// New is a convenient alias for Root().New
|
||||
func New(ctx ...interface{}) Logger {
|
||||
return root.New(ctx...)
|
||||
}
|
||||
|
||||
// Root returns the root logger
|
||||
func Root() Logger {
|
||||
return root
|
||||
}
|
||||
|
||||
// The following functions bypass the exported logger methods (logger.Debug,
|
||||
// etc.) to keep the call depth the same for all paths to logger.write so
|
||||
// runtime.Caller(2) always refers to the call site in client code.
|
||||
|
||||
// Debug is a convenient alias for Root().Debug
|
||||
func Debug(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlDebug, ctx)
|
||||
}
|
||||
|
||||
// Info is a convenient alias for Root().Info
|
||||
func Info(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlInfo, ctx)
|
||||
}
|
||||
|
||||
// Warn is a convenient alias for Root().Warn
|
||||
func Warn(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlWarn, ctx)
|
||||
}
|
||||
|
||||
// Error is a convenient alias for Root().Error
|
||||
func Error(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlError, ctx)
|
||||
}
|
||||
|
||||
// Crit is a convenient alias for Root().Crit
|
||||
func Crit(msg string, ctx ...interface{}) {
|
||||
root.write(msg, LvlCrit, ctx)
|
||||
}
|
||||
55
Godeps/_workspace/src/github.com/inconshreveable/log15/syslog.go
generated
vendored
Normal file
55
Godeps/_workspace/src/github.com/inconshreveable/log15/syslog.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// +build !windows,!plan9
|
||||
|
||||
package log15
|
||||
|
||||
import (
|
||||
"log/syslog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SyslogHandler opens a connection to the system syslog daemon by calling
|
||||
// syslog.New and writes all records to it.
|
||||
func SyslogHandler(priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
|
||||
wr, err := syslog.New(priority, tag)
|
||||
return sharedSyslog(fmtr, wr, err)
|
||||
}
|
||||
|
||||
// SyslogHandler opens a connection to a log daemon over the network and writes
|
||||
// all log records to it.
|
||||
func SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
|
||||
wr, err := syslog.Dial(net, addr, priority, tag)
|
||||
return sharedSyslog(fmtr, wr, err)
|
||||
}
|
||||
|
||||
func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := FuncHandler(func(r *Record) error {
|
||||
var syslogFn = sysWr.Info
|
||||
switch r.Lvl {
|
||||
case LvlCrit:
|
||||
syslogFn = sysWr.Crit
|
||||
case LvlError:
|
||||
syslogFn = sysWr.Err
|
||||
case LvlWarn:
|
||||
syslogFn = sysWr.Warning
|
||||
case LvlInfo:
|
||||
syslogFn = sysWr.Info
|
||||
case LvlDebug:
|
||||
syslogFn = sysWr.Debug
|
||||
}
|
||||
|
||||
s := strings.TrimSpace(string(fmtr.Format(r)))
|
||||
return syslogFn(s)
|
||||
})
|
||||
return LazyHandler(&closingHandler{sysWr, h}), nil
|
||||
}
|
||||
|
||||
func (m muster) SyslogHandler(priority syslog.Priority, tag string, fmtr Format) Handler {
|
||||
return must(SyslogHandler(priority, tag, fmtr))
|
||||
}
|
||||
|
||||
func (m muster) SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) Handler {
|
||||
return must(SyslogNetHandler(net, addr, priority, tag, fmtr))
|
||||
}
|
||||
21
Godeps/_workspace/src/github.com/inconshreveable/log15/term/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/inconshreveable/log15/term/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Simon Eskildsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
13
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_appengine.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_appengine.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package term
|
||||
|
||||
// IsTty always returns false on AppEngine.
|
||||
func IsTty(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_darwin.go
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package term
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
18
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_freebsd.go
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
// Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]uint8
|
||||
Ispeed uint32
|
||||
Ospeed uint32
|
||||
}
|
||||
14
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_linux.go
generated
vendored
Normal file
14
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_linux.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package term
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
||||
20
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_notwindows.go
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_notwindows.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux,!appengine darwin freebsd openbsd
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTty returns true if the given file descriptor is a terminal.
|
||||
func IsTty(fd uintptr) bool {
|
||||
var termios Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
7
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_openbsd.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_openbsd.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package term
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
26
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_windows.go
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_windows.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTty returns true if the given file descriptor is a terminal.
|
||||
func IsTty(fd uintptr) bool {
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
20
Godeps/_workspace/src/github.com/influxdata/influxdb/LICENSE
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/influxdata/influxdb/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2016 Errplane Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
27
Godeps/_workspace/src/github.com/influxdata/influxdb/LICENSE_OF_DEPENDENCIES.md
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/influxdata/influxdb/LICENSE_OF_DEPENDENCIES.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# List
|
||||
- bootstrap 3.3.5 [MIT LICENSE](https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
- collectd.org [ISC LICENSE](https://github.com/collectd/go-collectd/blob/master/LICENSE)
|
||||
- github.com/armon/go-metrics [MIT LICENSE](https://github.com/armon/go-metrics/blob/master/LICENSE)
|
||||
- github.com/BurntSushi/toml [WTFPL LICENSE](https://github.com/BurntSushi/toml/blob/master/COPYING)
|
||||
- github.com/bmizerany/pat [MIT LICENSE](https://github.com/bmizerany/pat#license)
|
||||
- github.com/boltdb/bolt [MIT LICENSE](https://github.com/boltdb/bolt/blob/master/LICENSE)
|
||||
- github.com/dgryski/go-bits [MIT LICENSE](https://github.com/dgryski/go-bits/blob/master/LICENSE)
|
||||
- github.com/dgryski/go-bitstream [MIT LICENSE](https://github.com/dgryski/go-bitstream/blob/master/LICENSE)
|
||||
- github.com/gogo/protobuf/proto [BSD LICENSE](https://github.com/gogo/protobuf/blob/master/LICENSE)
|
||||
- github.com/davecgh/go-spew/spew [ISC LICENSE](https://github.com/davecgh/go-spew/blob/master/LICENSE)
|
||||
- github.com/golang/snappy [BSD LICENSE](https://github.com/golang/snappy/blob/master/LICENSE)
|
||||
- github.com/hashicorp/go-msgpack [BSD LICENSE](https://github.com/hashicorp/go-msgpack/blob/master/LICENSE)
|
||||
- github.com/hashicorp/raft [MPL LICENSE](https://github.com/hashicorp/raft/blob/master/LICENSE)
|
||||
- github.com/hashicorp/raft-boltdb [MOZILLA PUBLIC LICENSE](https://github.com/hashicorp/raft-boltdb/blob/master/LICENSE)
|
||||
- github.com/influxdata/usage-client [MIT LICENSE](https://github.com/influxdata/usage-client/blob/master/LICENSE.txt)
|
||||
- github.com/jwilder/encoding [MIT LICENSE](https://github.com/jwilder/encoding/blob/master/LICENSE)
|
||||
- github.com/kimor79/gollectd [BSD LICENSE](https://github.com/kimor79/gollectd/blob/master/LICENSE)
|
||||
- github.com/paulbellamy/ratecounter [MIT LICENSE](https://github.com/paulbellamy/ratecounter/blob/master/LICENSE)
|
||||
- github.com/peterh/liner [MIT LICENSE](https://github.com/peterh/liner/blob/master/COPYING)
|
||||
- github.com/rakyll/statik [APACHE LICENSE](https://github.com/rakyll/statik/blob/master/LICENSE)
|
||||
- glyphicons [LICENSE](http://glyphicons.com/license/)
|
||||
- golang.org/x/crypto [BSD LICENSE](https://github.com/golang/crypto/blob/master/LICENSE)
|
||||
- golang.org/x/tools [BSD LICENSE](https://github.com/golang/tools/blob/master/LICENSE)
|
||||
- gopkg.in/fatih/pool.v2 [MIT LICENSE](https://github.com/fatih/pool/blob/v2.0.0/LICENSE)
|
||||
- jquery 2.1.4 [MIT LICENSE](https://github.com/jquery/jquery/blob/master/LICENSE.txt)
|
||||
- react 0.13.3 [BSD LICENSE](https://github.com/facebook/react/blob/master/LICENSE)
|
||||
8
Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml
generated
vendored
8
Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml
generated
vendored
@@ -1,9 +1,13 @@
|
||||
language: go
|
||||
sudo: required
|
||||
dist: trusty
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx
|
||||
- go test -v . -tags "libsqlite3"
|
||||
|
||||
27
Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md
generated
vendored
27
Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md
generated
vendored
@@ -1,8 +1,9 @@
|
||||
go-sqlite3
|
||||
==========
|
||||
|
||||
[](https://travis-ci.org/mattn/go-sqlite3)
|
||||
[](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
|
||||
[](https://travis-ci.org/mattn/go-sqlite3)
|
||||
[](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
|
||||
[](http://godoc.org/github.com/mattn/go-sqlite3)
|
||||
|
||||
Description
|
||||
-----------
|
||||
@@ -16,6 +17,10 @@ This package can be installed with the go get command:
|
||||
|
||||
go get github.com/mattn/go-sqlite3
|
||||
|
||||
_go-sqlite3_ is *cgo* package.
|
||||
If you want to build your app using go-sqlite3, you need gcc.
|
||||
However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
@@ -26,6 +31,20 @@ Examples can be found under the `./_example` directory
|
||||
FAQ
|
||||
---
|
||||
|
||||
* Want to build go-sqlite3 with libsqlite3 on my linux.
|
||||
|
||||
Use `go build --tags "libsqlite3 linux"`
|
||||
|
||||
* Want to build go-sqlite3 with libsqlite3 on OS X.
|
||||
|
||||
Install sqlite3 from homebrew: `brew install sqlite3`
|
||||
|
||||
Use `go build --tags "libsqlite3 darwin"`
|
||||
|
||||
* Want to build go-sqlite3 with icu extension.
|
||||
|
||||
Use `go build --tags "icu"`
|
||||
|
||||
* Can't build go-sqlite3 on windows 64bit.
|
||||
|
||||
> Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit.
|
||||
@@ -36,7 +55,7 @@ FAQ
|
||||
> You can pass some arguments into the connection string, for example, a URI.
|
||||
> See: https://github.com/mattn/go-sqlite3/issues/39
|
||||
|
||||
* Do you want cross compiling? mingw on Linux or Mac?
|
||||
* Do you want to cross compile? mingw on Linux or Mac?
|
||||
|
||||
> See: https://github.com/mattn/go-sqlite3/issues/106
|
||||
> See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html
|
||||
@@ -54,7 +73,7 @@ sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h
|
||||
|
||||
The -binding suffix was added to avoid build failures under gccgo.
|
||||
|
||||
In this repository, those files are amalgamation code that copied from SQLite3. The license of those codes are depend on the license of SQLite3.
|
||||
In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
4
Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go
generated
vendored
4
Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go
generated
vendored
@@ -6,7 +6,11 @@
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#ifndef USE_LIBSQLITE3
|
||||
#include <sqlite3-binding.h>
|
||||
#else
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
336
Godeps/_workspace/src/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
336
Godeps/_workspace/src/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
// You can't export a Go function to C and have definitions in the C
|
||||
// preamble in the same file, so we have to have callbackTrampoline in
|
||||
// its own file. Because we need a separate file anyway, the support
|
||||
// code for SQLite custom functions is in here.
|
||||
|
||||
/*
|
||||
#include <sqlite3-binding.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
|
||||
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//export callbackTrampoline
|
||||
func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
|
||||
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||
fi := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*functionInfo)
|
||||
fi.Call(ctx, args)
|
||||
}
|
||||
|
||||
//export stepTrampoline
|
||||
func stepTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
|
||||
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||
ai := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*aggInfo)
|
||||
ai.Step(ctx, args)
|
||||
}
|
||||
|
||||
//export doneTrampoline
|
||||
func doneTrampoline(ctx *C.sqlite3_context) {
|
||||
handle := uintptr(C.sqlite3_user_data(ctx))
|
||||
ai := lookupHandle(handle).(*aggInfo)
|
||||
ai.Done(ctx)
|
||||
}
|
||||
|
||||
// Use handles to avoid passing Go pointers to C.
|
||||
|
||||
type handleVal struct {
|
||||
db *SQLiteConn
|
||||
val interface{}
|
||||
}
|
||||
|
||||
var handleLock sync.Mutex
|
||||
var handleVals = make(map[uintptr]handleVal)
|
||||
var handleIndex uintptr = 100
|
||||
|
||||
func newHandle(db *SQLiteConn, v interface{}) uintptr {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
i := handleIndex
|
||||
handleIndex++
|
||||
handleVals[i] = handleVal{db, v}
|
||||
return i
|
||||
}
|
||||
|
||||
func lookupHandle(handle uintptr) interface{} {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
r, ok := handleVals[handle]
|
||||
if !ok {
|
||||
if handle >= 100 && handle < handleIndex {
|
||||
panic("deleted handle")
|
||||
} else {
|
||||
panic("invalid handle")
|
||||
}
|
||||
}
|
||||
return r.val
|
||||
}
|
||||
|
||||
func deleteHandles(db *SQLiteConn) {
|
||||
handleLock.Lock()
|
||||
defer handleLock.Unlock()
|
||||
for handle, val := range handleVals {
|
||||
if val.db == db {
|
||||
delete(handleVals, handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is only here so that tests can refer to it.
|
||||
type callbackArgRaw C.sqlite3_value
|
||||
|
||||
type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error)
|
||||
|
||||
type callbackArgCast struct {
|
||||
f callbackArgConverter
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
val, err := c.f(v)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
if !val.Type().ConvertibleTo(c.typ) {
|
||||
return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ)
|
||||
}
|
||||
return val.Convert(c.typ), nil
|
||||
}
|
||||
|
||||
func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||
}
|
||||
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
|
||||
}
|
||||
|
||||
func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||
}
|
||||
i := int64(C.sqlite3_value_int64(v))
|
||||
val := false
|
||||
if i != 0 {
|
||||
val = true
|
||||
}
|
||||
return reflect.ValueOf(val), nil
|
||||
}
|
||||
|
||||
func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
|
||||
return reflect.Value{}, fmt.Errorf("argument must be a FLOAT")
|
||||
}
|
||||
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
|
||||
}
|
||||
|
||||
func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_BLOB:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
p := C.sqlite3_value_blob(v)
|
||||
return reflect.ValueOf(C.GoBytes(p, l)), nil
|
||||
case C.SQLITE_TEXT:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
c := unsafe.Pointer(C.sqlite3_value_text(v))
|
||||
return reflect.ValueOf(C.GoBytes(c, l)), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_BLOB:
|
||||
l := C.sqlite3_value_bytes(v)
|
||||
p := (*C.char)(C.sqlite3_value_blob(v))
|
||||
return reflect.ValueOf(C.GoStringN(p, l)), nil
|
||||
case C.SQLITE_TEXT:
|
||||
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
|
||||
return reflect.ValueOf(C.GoString(c)), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) {
|
||||
switch C.sqlite3_value_type(v) {
|
||||
case C.SQLITE_INTEGER:
|
||||
return callbackArgInt64(v)
|
||||
case C.SQLITE_FLOAT:
|
||||
return callbackArgFloat64(v)
|
||||
case C.SQLITE_TEXT:
|
||||
return callbackArgString(v)
|
||||
case C.SQLITE_BLOB:
|
||||
return callbackArgBytes(v)
|
||||
case C.SQLITE_NULL:
|
||||
// Interpret NULL as a nil byte slice.
|
||||
var ret []byte
|
||||
return reflect.ValueOf(ret), nil
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Interface:
|
||||
if typ.NumMethod() != 0 {
|
||||
return nil, errors.New("the only supported interface type is interface{}")
|
||||
}
|
||||
return callbackArgGeneric, nil
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() != reflect.Uint8 {
|
||||
return nil, errors.New("the only supported slice type is []byte")
|
||||
}
|
||||
return callbackArgBytes, nil
|
||||
case reflect.String:
|
||||
return callbackArgString, nil
|
||||
case reflect.Bool:
|
||||
return callbackArgBool, nil
|
||||
case reflect.Int64:
|
||||
return callbackArgInt64, nil
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
c := callbackArgCast{callbackArgInt64, typ}
|
||||
return c.Run, nil
|
||||
case reflect.Float64:
|
||||
return callbackArgFloat64, nil
|
||||
case reflect.Float32:
|
||||
c := callbackArgCast{callbackArgFloat64, typ}
|
||||
return c.Run, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func callbackConvertArgs(argv []*C.sqlite3_value, converters []callbackArgConverter, variadic callbackArgConverter) ([]reflect.Value, error) {
|
||||
var args []reflect.Value
|
||||
|
||||
if len(argv) < len(converters) {
|
||||
return nil, fmt.Errorf("function requires at least %d arguments", len(converters))
|
||||
}
|
||||
|
||||
for i, arg := range argv[:len(converters)] {
|
||||
v, err := converters[i](arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
|
||||
if variadic != nil {
|
||||
for _, arg := range argv[len(converters):] {
|
||||
v, err := variadic(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error
|
||||
|
||||
func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int64:
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
v = v.Convert(reflect.TypeOf(int64(0)))
|
||||
case reflect.Bool:
|
||||
b := v.Interface().(bool)
|
||||
if b {
|
||||
v = reflect.ValueOf(int64(1))
|
||||
} else {
|
||||
v = reflect.ValueOf(int64(0))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("cannot convert %s to INTEGER", v.Type())
|
||||
}
|
||||
|
||||
C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Float64:
|
||||
case reflect.Float32:
|
||||
v = v.Convert(reflect.TypeOf(float64(0)))
|
||||
default:
|
||||
return fmt.Errorf("cannot convert %s to FLOAT", v.Type())
|
||||
}
|
||||
|
||||
C.sqlite3_result_double(ctx, C.double(v.Interface().(float64)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 {
|
||||
return fmt.Errorf("cannot convert %s to BLOB", v.Type())
|
||||
}
|
||||
i := v.Interface()
|
||||
if i == nil || len(i.([]byte)) == 0 {
|
||||
C.sqlite3_result_null(ctx)
|
||||
} else {
|
||||
bs := i.([]byte)
|
||||
C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||
if v.Type().Kind() != reflect.String {
|
||||
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
|
||||
}
|
||||
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() != reflect.Uint8 {
|
||||
return nil, errors.New("the only supported slice type is []byte")
|
||||
}
|
||||
return callbackRetBlob, nil
|
||||
case reflect.String:
|
||||
return callbackRetText, nil
|
||||
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||
return callbackRetInteger, nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return callbackRetFloat, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func callbackError(ctx *C.sqlite3_context, err error) {
|
||||
cstr := C.CString(err.Error())
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
C.sqlite3_result_error(ctx, cstr, -1)
|
||||
}
|
||||
|
||||
// Test support code. Tests are not allowed to import "C", so we can't
|
||||
// declare any functions that use C.sqlite3_value.
|
||||
func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter {
|
||||
return func(*C.sqlite3_value) (reflect.Value, error) {
|
||||
return v, err
|
||||
}
|
||||
}
|
||||
41
Godeps/_workspace/src/github.com/mattn/go-sqlite3/doc.go
generated
vendored
41
Godeps/_workspace/src/github.com/mattn/go-sqlite3/doc.go
generated
vendored
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
Package sqlite3 provides interface to SQLite3 databases.
|
||||
|
||||
This works as driver for database/sql.
|
||||
This works as a driver for database/sql.
|
||||
|
||||
Installation
|
||||
|
||||
@@ -9,7 +9,7 @@ Installation
|
||||
|
||||
Supported Types
|
||||
|
||||
Currently, go-sqlite3 support following data types.
|
||||
Currently, go-sqlite3 supports the following data types.
|
||||
|
||||
+------------------------------+
|
||||
|go | sqlite3 |
|
||||
@@ -26,14 +26,14 @@ Currently, go-sqlite3 support following data types.
|
||||
|
||||
SQLite3 Extension
|
||||
|
||||
You can write your own extension module for sqlite3. For example, below is a
|
||||
extension for Regexp matcher operation.
|
||||
You can write your own extension module for sqlite3. For example, below is an
|
||||
extension for a Regexp matcher operation.
|
||||
|
||||
#include <pcre.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sqlite3ext.h>
|
||||
|
||||
|
||||
SQLITE_EXTENSION_INIT1
|
||||
static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
||||
if (argc >= 2) {
|
||||
@@ -44,7 +44,7 @@ extension for Regexp matcher operation.
|
||||
int vec[500];
|
||||
int n, rc;
|
||||
pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
|
||||
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
|
||||
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
|
||||
if (rc <= 0) {
|
||||
sqlite3_result_error(context, errstr, 0);
|
||||
return;
|
||||
@@ -52,7 +52,7 @@ extension for Regexp matcher operation.
|
||||
sqlite3_result_int(context, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@@ -63,8 +63,8 @@ extension for Regexp matcher operation.
|
||||
(void*)db, regexp_func, NULL, NULL);
|
||||
}
|
||||
|
||||
It need to build as so/dll shared library. And you need to register
|
||||
extension module like below.
|
||||
It needs to be built as a so/dll shared library. And you need to register
|
||||
the extension module like below.
|
||||
|
||||
sql.Register("sqlite3_with_extensions",
|
||||
&sqlite3.SQLiteDriver{
|
||||
@@ -79,9 +79,9 @@ Then, you can use this extension.
|
||||
|
||||
Connection Hook
|
||||
|
||||
You can hook and inject your codes when connection established. database/sql
|
||||
doesn't provide the way to get native go-sqlite3 interfaces. So if you want,
|
||||
you need to hook ConnectHook and get the SQLiteConn.
|
||||
You can hook and inject your code when the connection is established. database/sql
|
||||
doesn't provide a way to get native go-sqlite3 interfaces. So if you want,
|
||||
you need to set ConnectHook and get the SQLiteConn.
|
||||
|
||||
sql.Register("sqlite3_with_hook_example",
|
||||
&sqlite3.SQLiteDriver{
|
||||
@@ -91,5 +91,22 @@ you need to hook ConnectHook and get the SQLiteConn.
|
||||
},
|
||||
})
|
||||
|
||||
Go SQlite3 Extensions
|
||||
|
||||
If you want to register Go functions as SQLite extension functions,
|
||||
call RegisterFunction from ConnectHook.
|
||||
|
||||
regex = func(re, s string) (bool, error) {
|
||||
return regexp.MatchString(re, s)
|
||||
}
|
||||
sql.Register("sqlite3_with_go_func",
|
||||
&sqlite3.SQLiteDriver{
|
||||
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||
return conn.RegisterFunc("regexp", regex, true)
|
||||
},
|
||||
})
|
||||
|
||||
See the documentation of RegisterFunc for more details.
|
||||
|
||||
*/
|
||||
package sqlite3
|
||||
|
||||
242
Godeps/_workspace/src/github.com/mattn/go-sqlite3/error_test.go
generated
vendored
242
Godeps/_workspace/src/github.com/mattn/go-sqlite3/error_test.go
generated
vendored
@@ -1,242 +0,0 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleError(t *testing.T) {
|
||||
e := ErrError.Error()
|
||||
if e != "SQL logic error or missing database" {
|
||||
t.Error("wrong error code:" + e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorruptDbErrors(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
f, err := os.Create(dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
f.Write([]byte{1, 2, 3, 4, 5})
|
||||
f.Close()
|
||||
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err == nil {
|
||||
_, err = db.Exec("drop table foo")
|
||||
}
|
||||
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrNotADB {
|
||||
t.Error("wrong error code for corrupted DB")
|
||||
}
|
||||
if err.Error() == "" {
|
||||
t.Error("wrong error string for corrupted DB")
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func TestSqlLogicErrors(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
const expectedErr = "table Foo already exists"
|
||||
_, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
|
||||
if err.Error() != expectedErr {
|
||||
t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_ForeignKey(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (100, 100);")
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintForeignKey {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintForeignKey)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_NotNull(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
|
||||
if err != nil {
|
||||
t.Fatalf("Creating first row: %v", err)
|
||||
}
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatalf("Retrieving last insert id: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref) VALUES (?);", id)
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintNotNull {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintNotNull)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtendedErrorCodes_Unique(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "sqlite3-err")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
dbFileName := path.Join(dirName, "test.db")
|
||||
db, err := sql.Open("sqlite3", dbFileName)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("PRAGMA foreign_keys=ON;")
|
||||
if err != nil {
|
||||
t.Errorf("PRAGMA foreign_keys=ON: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE Foo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
ref INTEGER NULL REFERENCES Foo (id),
|
||||
UNIQUE(value)
|
||||
);`)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
|
||||
if err != nil {
|
||||
t.Fatalf("Creating first row: %v", err)
|
||||
}
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatalf("Retrieving last insert id: %v", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (?, 100);", id)
|
||||
if err == nil {
|
||||
t.Error("No error!")
|
||||
} else {
|
||||
sqliteErr := err.(Error)
|
||||
if sqliteErr.Code != ErrConstraint {
|
||||
t.Errorf("Wrong basic error code: %d != %d",
|
||||
sqliteErr.Code, ErrConstraint)
|
||||
}
|
||||
if sqliteErr.ExtendedCode != ErrConstraintUnique {
|
||||
t.Errorf("Wrong extended error code: %d != %d",
|
||||
sqliteErr.ExtendedCode, ErrConstraintUnique)
|
||||
}
|
||||
extended := sqliteErr.Code.Extend(3).Error()
|
||||
expected := "constraint failed"
|
||||
if extended != expected {
|
||||
t.Errorf("Wrong basic error code: %q != %q",
|
||||
extended, expected)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
68891
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
68891
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
File diff suppressed because it is too large
Load Diff
2594
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
2594
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
File diff suppressed because it is too large
Load Diff
465
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
465
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
@@ -8,8 +8,12 @@ package sqlite3
|
||||
/*
|
||||
#cgo CFLAGS: -std=gnu99
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
|
||||
#ifndef USE_LIBSQLITE3
|
||||
#include <sqlite3-binding.h>
|
||||
#else
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -25,6 +29,10 @@ package sqlite3
|
||||
# define SQLITE_OPEN_FULLMUTEX 0
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_DETERMINISTIC
|
||||
# define SQLITE_DETERMINISTIC 0
|
||||
#endif
|
||||
|
||||
static int
|
||||
_sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs) {
|
||||
#ifdef SQLITE_OPEN_URI
|
||||
@@ -48,24 +56,49 @@ _sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
|
||||
#include <stdint.h>
|
||||
|
||||
static int
|
||||
_sqlite3_exec(sqlite3* db, const char* pcmd, long* rowid, long* changes)
|
||||
_sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv = sqlite3_exec(db, pcmd, 0, 0, 0);
|
||||
*rowid = (long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long) sqlite3_changes(db);
|
||||
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long long) sqlite3_changes(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_step(sqlite3_stmt* stmt, long* rowid, long* changes)
|
||||
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv = sqlite3_step(stmt);
|
||||
sqlite3* db = sqlite3_db_handle(stmt);
|
||||
*rowid = (long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long) sqlite3_changes(db);
|
||||
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long long) sqlite3_changes(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
|
||||
sqlite3_result_text(ctx, s, -1, &free);
|
||||
}
|
||||
|
||||
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l) {
|
||||
sqlite3_result_blob(ctx, b, l, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
int _sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
uintptr_t pApp,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
) {
|
||||
return sqlite3_create_function(db, zFunctionName, nArg, eTextRep, (void*) pApp, xFunc, xStep, xFinal);
|
||||
}
|
||||
|
||||
void callbackTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||
void stepTrampoline(sqlite3_context*, int, sqlite3_value**);
|
||||
void doneTrampoline(sqlite3_context*);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
@@ -75,6 +108,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -87,6 +121,10 @@ import (
|
||||
// into the database. When parsing a string from a timestamp or
|
||||
// datetime column, the formats are tried in order.
|
||||
var SQLiteTimestampFormats = []string{
|
||||
// By default, store timestamps with whatever timezone they come with.
|
||||
// When parsed, they will be returned with the same timezone.
|
||||
"2006-01-02 15:04:05.999999999-07:00",
|
||||
"2006-01-02T15:04:05.999999999-07:00",
|
||||
"2006-01-02 15:04:05.999999999",
|
||||
"2006-01-02T15:04:05.999999999",
|
||||
"2006-01-02 15:04:05",
|
||||
@@ -94,14 +132,13 @@ var SQLiteTimestampFormats = []string{
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02T15:04",
|
||||
"2006-01-02",
|
||||
"2006-01-02 15:04:05-07:00",
|
||||
}
|
||||
|
||||
func init() {
|
||||
sql.Register("sqlite3", &SQLiteDriver{})
|
||||
}
|
||||
|
||||
// Return SQLite library Version information.
|
||||
// Version returns SQLite library version information.
|
||||
func Version() (libVersion string, libVersionNumber int, sourceId string) {
|
||||
libVersion = C.GoString(C.sqlite3_libversion())
|
||||
libVersionNumber = int(C.sqlite3_libversion_number())
|
||||
@@ -117,8 +154,11 @@ type SQLiteDriver struct {
|
||||
|
||||
// Conn struct.
|
||||
type SQLiteConn struct {
|
||||
db *C.sqlite3
|
||||
loc *time.Location
|
||||
db *C.sqlite3
|
||||
loc *time.Location
|
||||
txlock string
|
||||
funcs []*functionInfo
|
||||
aggregators []*aggInfo
|
||||
}
|
||||
|
||||
// Tx struct.
|
||||
@@ -152,6 +192,107 @@ type SQLiteRows struct {
|
||||
cls bool
|
||||
}
|
||||
|
||||
type functionInfo struct {
|
||||
f reflect.Value
|
||||
argConverters []callbackArgConverter
|
||||
variadicConverter callbackArgConverter
|
||||
retConverter callbackRetConverter
|
||||
}
|
||||
|
||||
func (fi *functionInfo) Call(ctx *C.sqlite3_context, argv []*C.sqlite3_value) {
|
||||
args, err := callbackConvertArgs(argv, fi.argConverters, fi.variadicConverter)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := fi.f.Call(args)
|
||||
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
callbackError(ctx, ret[1].Interface().(error))
|
||||
return
|
||||
}
|
||||
|
||||
err = fi.retConverter(ctx, ret[0])
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type aggInfo struct {
|
||||
constructor reflect.Value
|
||||
|
||||
// Active aggregator objects for aggregations in flight. The
|
||||
// aggregators are indexed by a counter stored in the aggregation
|
||||
// user data space provided by sqlite.
|
||||
active map[int64]reflect.Value
|
||||
next int64
|
||||
|
||||
stepArgConverters []callbackArgConverter
|
||||
stepVariadicConverter callbackArgConverter
|
||||
|
||||
doneRetConverter callbackRetConverter
|
||||
}
|
||||
|
||||
func (ai *aggInfo) agg(ctx *C.sqlite3_context) (int64, reflect.Value, error) {
|
||||
aggIdx := (*int64)(C.sqlite3_aggregate_context(ctx, C.int(8)))
|
||||
if *aggIdx == 0 {
|
||||
*aggIdx = ai.next
|
||||
ret := ai.constructor.Call(nil)
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
return 0, reflect.Value{}, ret[1].Interface().(error)
|
||||
}
|
||||
if ret[0].IsNil() {
|
||||
return 0, reflect.Value{}, errors.New("aggregator constructor returned nil state")
|
||||
}
|
||||
ai.next++
|
||||
ai.active[*aggIdx] = ret[0]
|
||||
}
|
||||
return *aggIdx, ai.active[*aggIdx], nil
|
||||
}
|
||||
|
||||
func (ai *aggInfo) Step(ctx *C.sqlite3_context, argv []*C.sqlite3_value) {
|
||||
_, agg, err := ai.agg(ctx)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
args, err := callbackConvertArgs(argv, ai.stepArgConverters, ai.stepVariadicConverter)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := agg.MethodByName("Step").Call(args)
|
||||
if len(ret) == 1 && ret[0].Interface() != nil {
|
||||
callbackError(ctx, ret[0].Interface().(error))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (ai *aggInfo) Done(ctx *C.sqlite3_context) {
|
||||
idx, agg, err := ai.agg(ctx)
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
defer func() { delete(ai.active, idx) }()
|
||||
|
||||
ret := agg.MethodByName("Done").Call(nil)
|
||||
if len(ret) == 2 && ret[1].Interface() != nil {
|
||||
callbackError(ctx, ret[1].Interface().(error))
|
||||
return
|
||||
}
|
||||
|
||||
err = ai.doneRetConverter(ctx, ret[0])
|
||||
if err != nil {
|
||||
callbackError(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Commit transaction.
|
||||
func (tx *SQLiteTx) Commit() error {
|
||||
_, err := tx.c.exec("COMMIT")
|
||||
@@ -164,6 +305,208 @@ func (tx *SQLiteTx) Rollback() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// RegisterFunc makes a Go function available as a SQLite function.
|
||||
//
|
||||
// The Go function can have arguments of the following types: any
|
||||
// numeric type except complex, bool, []byte, string and
|
||||
// interface{}. interface{} arguments are given the direct translation
|
||||
// of the SQLite data type: int64 for INTEGER, float64 for FLOAT,
|
||||
// []byte for BLOB, string for TEXT.
|
||||
//
|
||||
// The function can additionally be variadic, as long as the type of
|
||||
// the variadic argument is one of the above.
|
||||
//
|
||||
// If pure is true. SQLite will assume that the function's return
|
||||
// value depends only on its inputs, and make more aggressive
|
||||
// optimizations in its queries.
|
||||
//
|
||||
// See _example/go_custom_funcs for a detailed example.
|
||||
func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) error {
|
||||
var fi functionInfo
|
||||
fi.f = reflect.ValueOf(impl)
|
||||
t := fi.f.Type()
|
||||
if t.Kind() != reflect.Func {
|
||||
return errors.New("Non-function passed to RegisterFunc")
|
||||
}
|
||||
if t.NumOut() != 1 && t.NumOut() != 2 {
|
||||
return errors.New("SQLite functions must return 1 or 2 values")
|
||||
}
|
||||
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("Second return value of SQLite function must be error")
|
||||
}
|
||||
|
||||
numArgs := t.NumIn()
|
||||
if t.IsVariadic() {
|
||||
numArgs--
|
||||
}
|
||||
|
||||
for i := 0; i < numArgs; i++ {
|
||||
conv, err := callbackArg(t.In(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.argConverters = append(fi.argConverters, conv)
|
||||
}
|
||||
|
||||
if t.IsVariadic() {
|
||||
conv, err := callbackArg(t.In(numArgs).Elem())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.variadicConverter = conv
|
||||
// Pass -1 to sqlite so that it allows any number of
|
||||
// arguments. The call helper verifies that the minimum number
|
||||
// of arguments is present for variadic functions.
|
||||
numArgs = -1
|
||||
}
|
||||
|
||||
conv, err := callbackRet(t.Out(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.retConverter = conv
|
||||
|
||||
// fi must outlast the database connection, or we'll have dangling pointers.
|
||||
c.funcs = append(c.funcs, &fi)
|
||||
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
opts := C.SQLITE_UTF8
|
||||
if pure {
|
||||
opts |= C.SQLITE_DETERMINISTIC
|
||||
}
|
||||
rv := C._sqlite3_create_function(c.db, cname, C.int(numArgs), C.int(opts), C.uintptr_t(newHandle(c, &fi)), (*[0]byte)(unsafe.Pointer(C.callbackTrampoline)), nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAggregator makes a Go type available as a SQLite aggregation function.
|
||||
//
|
||||
// Because aggregation is incremental, it's implemented in Go with a
|
||||
// type that has 2 methods: func Step(values) accumulates one row of
|
||||
// data into the accumulator, and func Done() ret finalizes and
|
||||
// returns the aggregate value. "values" and "ret" may be any type
|
||||
// supported by RegisterFunc.
|
||||
//
|
||||
// RegisterAggregator takes as implementation a constructor function
|
||||
// that constructs an instance of the aggregator type each time an
|
||||
// aggregation begins. The constructor must return a pointer to a
|
||||
// type, or an interface that implements Step() and Done().
|
||||
//
|
||||
// The constructor function and the Step/Done methods may optionally
|
||||
// return an error in addition to their other return values.
|
||||
//
|
||||
// See _example/go_custom_funcs for a detailed example.
|
||||
func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error {
|
||||
var ai aggInfo
|
||||
ai.constructor = reflect.ValueOf(impl)
|
||||
t := ai.constructor.Type()
|
||||
if t.Kind() != reflect.Func {
|
||||
return errors.New("non-function passed to RegisterAggregator")
|
||||
}
|
||||
if t.NumOut() != 1 && t.NumOut() != 2 {
|
||||
return errors.New("SQLite aggregator constructors must return 1 or 2 values")
|
||||
}
|
||||
if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("Second return value of SQLite function must be error")
|
||||
}
|
||||
if t.NumIn() != 0 {
|
||||
return errors.New("SQLite aggregator constructors must not have arguments")
|
||||
}
|
||||
|
||||
agg := t.Out(0)
|
||||
switch agg.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
default:
|
||||
return errors.New("SQlite aggregator constructor must return a pointer object")
|
||||
}
|
||||
stepFn, found := agg.MethodByName("Step")
|
||||
if !found {
|
||||
return errors.New("SQlite aggregator doesn't have a Step() function")
|
||||
}
|
||||
step := stepFn.Type
|
||||
if step.NumOut() != 0 && step.NumOut() != 1 {
|
||||
return errors.New("SQlite aggregator Step() function must return 0 or 1 values")
|
||||
}
|
||||
if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("type of SQlite aggregator Step() return value must be error")
|
||||
}
|
||||
|
||||
stepNArgs := step.NumIn()
|
||||
start := 0
|
||||
if agg.Kind() == reflect.Ptr {
|
||||
// Skip over the method receiver
|
||||
stepNArgs--
|
||||
start++
|
||||
}
|
||||
if step.IsVariadic() {
|
||||
stepNArgs--
|
||||
}
|
||||
for i := start; i < start+stepNArgs; i++ {
|
||||
conv, err := callbackArg(step.In(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.stepArgConverters = append(ai.stepArgConverters, conv)
|
||||
}
|
||||
if step.IsVariadic() {
|
||||
conv, err := callbackArg(t.In(start + stepNArgs).Elem())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.stepVariadicConverter = conv
|
||||
// Pass -1 to sqlite so that it allows any number of
|
||||
// arguments. The call helper verifies that the minimum number
|
||||
// of arguments is present for variadic functions.
|
||||
stepNArgs = -1
|
||||
}
|
||||
|
||||
doneFn, found := agg.MethodByName("Done")
|
||||
if !found {
|
||||
return errors.New("SQlite aggregator doesn't have a Done() function")
|
||||
}
|
||||
done := doneFn.Type
|
||||
doneNArgs := done.NumIn()
|
||||
if agg.Kind() == reflect.Ptr {
|
||||
// Skip over the method receiver
|
||||
doneNArgs--
|
||||
}
|
||||
if doneNArgs != 0 {
|
||||
return errors.New("SQlite aggregator Done() function must have no arguments")
|
||||
}
|
||||
if done.NumOut() != 1 && done.NumOut() != 2 {
|
||||
return errors.New("SQLite aggregator Done() function must return 1 or 2 values")
|
||||
}
|
||||
if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
return errors.New("second return value of SQLite aggregator Done() function must be error")
|
||||
}
|
||||
|
||||
conv, err := callbackRet(done.Out(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ai.doneRetConverter = conv
|
||||
ai.active = make(map[int64]reflect.Value)
|
||||
ai.next = 1
|
||||
|
||||
// ai must outlast the database connection, or we'll have dangling pointers.
|
||||
c.aggregators = append(c.aggregators, &ai)
|
||||
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
opts := C.SQLITE_UTF8
|
||||
if pure {
|
||||
opts |= C.SQLITE_DETERMINISTIC
|
||||
}
|
||||
rv := C._sqlite3_create_function(c.db, cname, C.int(stepNArgs), C.int(opts), C.uintptr_t(newHandle(c, &ai)), nil, (*[0]byte)(unsafe.Pointer(C.stepTrampoline)), (*[0]byte)(unsafe.Pointer(C.doneTrampoline)))
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoCommit return which currently auto commit or not.
|
||||
func (c *SQLiteConn) AutoCommit() bool {
|
||||
return int(C.sqlite3_get_autocommit(c.db)) != 0
|
||||
@@ -242,7 +585,7 @@ func (c *SQLiteConn) exec(cmd string) (driver.Result, error) {
|
||||
pcmd := C.CString(cmd)
|
||||
defer C.free(unsafe.Pointer(pcmd))
|
||||
|
||||
var rowid, changes C.long
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_exec(c.db, pcmd, &rowid, &changes)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, c.lastError()
|
||||
@@ -252,7 +595,7 @@ func (c *SQLiteConn) exec(cmd string) (driver.Result, error) {
|
||||
|
||||
// Begin transaction.
|
||||
func (c *SQLiteConn) Begin() (driver.Tx, error) {
|
||||
if _, err := c.exec("BEGIN"); err != nil {
|
||||
if _, err := c.exec(c.txlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SQLiteTx{c}, nil
|
||||
@@ -263,22 +606,26 @@ func errorString(err Error) string {
|
||||
}
|
||||
|
||||
// Open database and return a new connection.
|
||||
// You can specify DSN string with URI filename.
|
||||
// You can specify a DSN string using a URI as the filename.
|
||||
// test.db
|
||||
// file:test.db?cache=shared&mode=memory
|
||||
// :memory:
|
||||
// file::memory:
|
||||
// go-sqlite handle especially query parameters.
|
||||
// go-sqlite3 adds the following query parameters to those used by SQLite:
|
||||
// _loc=XXX
|
||||
// Specify location of time format. It's possible to specify "auto".
|
||||
// _busy_timeout=XXX
|
||||
// Specify value for sqlite3_busy_timeout.
|
||||
// _txlock=XXX
|
||||
// Specify locking behavior for transactions. XXX can be "immediate",
|
||||
// "deferred", "exclusive".
|
||||
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
if C.sqlite3_threadsafe() == 0 {
|
||||
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
|
||||
}
|
||||
|
||||
var loc *time.Location
|
||||
txlock := "BEGIN"
|
||||
busy_timeout := 5000
|
||||
pos := strings.IndexRune(dsn, '?')
|
||||
if pos >= 1 {
|
||||
@@ -308,6 +655,20 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
busy_timeout = int(iv)
|
||||
}
|
||||
|
||||
// _txlock
|
||||
if val := params.Get("_txlock"); val != "" {
|
||||
switch val {
|
||||
case "immediate":
|
||||
txlock = "BEGIN IMMEDIATE"
|
||||
case "exclusive":
|
||||
txlock = "BEGIN EXCLUSIVE"
|
||||
case "deferred":
|
||||
txlock = "BEGIN"
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _txlock: %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(dsn, "file:") {
|
||||
dsn = dsn[:pos]
|
||||
}
|
||||
@@ -333,26 +694,11 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
return nil, Error{Code: ErrNo(rv)}
|
||||
}
|
||||
|
||||
conn := &SQLiteConn{db: db, loc: loc}
|
||||
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
|
||||
|
||||
if len(d.Extensions) > 0 {
|
||||
rv = C.sqlite3_enable_load_extension(db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
}
|
||||
|
||||
for _, extension := range d.Extensions {
|
||||
cext := C.CString(extension)
|
||||
defer C.free(unsafe.Pointer(cext))
|
||||
rv = C.sqlite3_load_extension(db, cext, nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
}
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, errors.New(C.GoString(C.sqlite3_errmsg(db)))
|
||||
if err := conn.loadExtensions(d.Extensions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,6 +713,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
|
||||
// Close the connection.
|
||||
func (c *SQLiteConn) Close() error {
|
||||
deleteHandles(c)
|
||||
rv := C.sqlite3_close_v2(c.db)
|
||||
if rv != C.SQLITE_OK {
|
||||
return c.lastError()
|
||||
@@ -376,7 +723,7 @@ func (c *SQLiteConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prepare query string. Return a new statement.
|
||||
// Prepare the query string. Return a new statement.
|
||||
func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) {
|
||||
pquery := C.CString(query)
|
||||
defer C.free(unsafe.Pointer(pquery))
|
||||
@@ -476,13 +823,13 @@ func (s *SQLiteStmt) bind(args []driver.Value) error {
|
||||
case float64:
|
||||
rv = C.sqlite3_bind_double(s.s, n, C.double(v))
|
||||
case []byte:
|
||||
var p *byte
|
||||
if len(v) > 0 {
|
||||
p = &v[0]
|
||||
if len(v) == 0 {
|
||||
rv = C._sqlite3_bind_blob(s.s, n, nil, 0)
|
||||
} else {
|
||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(len(v)))
|
||||
}
|
||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v)))
|
||||
case time.Time:
|
||||
b := []byte(v.UTC().Format(SQLiteTimestampFormats[0]))
|
||||
b := []byte(v.Format(SQLiteTimestampFormats[0]))
|
||||
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
||||
}
|
||||
if rv != C.SQLITE_OK {
|
||||
@@ -517,7 +864,7 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||
C.sqlite3_clear_bindings(s.s)
|
||||
return nil, err
|
||||
}
|
||||
var rowid, changes C.long
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_step(s.s, &rowid, &changes)
|
||||
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
||||
err := s.c.lastError()
|
||||
@@ -554,6 +901,17 @@ func (rc *SQLiteRows) Columns() []string {
|
||||
return rc.cols
|
||||
}
|
||||
|
||||
// Return column types.
|
||||
func (rc *SQLiteRows) DeclTypes() []string {
|
||||
if rc.decltype == nil {
|
||||
rc.decltype = make([]string, rc.nc)
|
||||
for i := 0; i < rc.nc; i++ {
|
||||
rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
|
||||
}
|
||||
}
|
||||
return rc.decltype
|
||||
}
|
||||
|
||||
// Move cursor to next.
|
||||
func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
rv := C.sqlite3_step(rc.s.s)
|
||||
@@ -568,12 +926,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rc.decltype == nil {
|
||||
rc.decltype = make([]string, rc.nc)
|
||||
for i := 0; i < rc.nc; i++ {
|
||||
rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
|
||||
}
|
||||
}
|
||||
rc.DeclTypes()
|
||||
|
||||
for i := range dest {
|
||||
switch C.sqlite3_column_type(rc.s.s, C.int(i)) {
|
||||
@@ -581,18 +934,15 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
val := int64(C.sqlite3_column_int64(rc.s.s, C.int(i)))
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
unixTimestamp := strconv.FormatInt(val, 10)
|
||||
var t time.Time
|
||||
if len(unixTimestamp) == 13 {
|
||||
duration, err := time.ParseDuration(unixTimestamp + "ms")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing %s value %d, %s", rc.decltype[i], val, err)
|
||||
}
|
||||
epoch := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
t = epoch.Add(duration)
|
||||
// Assume a millisecond unix timestamp if it's 13 digits -- too
|
||||
// large to be a reasonable timestamp in seconds.
|
||||
if val > 1e12 || val < -1e12 {
|
||||
val *= int64(time.Millisecond) // convert ms to nsec
|
||||
} else {
|
||||
t = time.Unix(val, 0)
|
||||
val *= int64(time.Second) // convert sec to nsec
|
||||
}
|
||||
t = time.Unix(0, val).UTC()
|
||||
if rc.s.c.loc != nil {
|
||||
t = t.In(rc.s.c.loc)
|
||||
}
|
||||
@@ -624,11 +974,14 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
case C.SQLITE_TEXT:
|
||||
var err error
|
||||
var timeVal time.Time
|
||||
s := C.GoString((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))))
|
||||
|
||||
n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i)))
|
||||
s := C.GoStringN((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))), C.int(n))
|
||||
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
var t time.Time
|
||||
s = strings.TrimSuffix(s, "Z")
|
||||
for _, format := range SQLiteTimestampFormats {
|
||||
if timeVal, err = time.ParseInLocation(format, s, time.UTC); err == nil {
|
||||
t = timeVal
|
||||
|
||||
83
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts3_test.go
generated
vendored
83
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts3_test.go
generated
vendored
@@ -1,83 +0,0 @@
|
||||
// Copyright (C) 2015 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFTS3(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts3(id INTEGER PRIMARY KEY, value TEXT)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `今日の 晩御飯は 天麩羅よ`)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert value:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 2, `今日は いい 天気だ`)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert value:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, value FROM foo WHERE value MATCH '今日* 天*'")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var value string
|
||||
|
||||
if err := rows.Scan(&id, &value); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if id == 1 && value != `今日の 晩御飯は 天麩羅よ` {
|
||||
t.Error("Value for id 1 should be `今日の 晩御飯は 天麩羅よ`, but:", value)
|
||||
} else if id == 2 && value != `今日は いい 天気だ` {
|
||||
t.Error("Value for id 2 should be `今日は いい 天気だ`, but:", value)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err = db.Query("SELECT value FROM foo WHERE value MATCH '今日* 天麩羅*'")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var value string
|
||||
if !rows.Next() {
|
||||
t.Fatal("Result should be only one")
|
||||
}
|
||||
|
||||
if err := rows.Scan(&value); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
|
||||
if value != `今日の 晩御飯は 天麩羅よ` {
|
||||
t.Fatal("Value should be `今日の 晩御飯は 天麩羅よ`, but:", value)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Fatal("Result should be only one")
|
||||
}
|
||||
}
|
||||
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts5.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_fts5.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build fts5
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS5
|
||||
#cgo LDFLAGS: -lm
|
||||
*/
|
||||
import "C"
|
||||
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_icu.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_icu.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build icu
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -licuuc -licui18n
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_ICU
|
||||
*/
|
||||
import "C"
|
||||
12
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_json1.go
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_json1.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build json1
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_JSON1
|
||||
*/
|
||||
import "C"
|
||||
14
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
14
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build libsqlite3
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DUSE_LIBSQLITE3
|
||||
#cgo linux LDFLAGS: -lsqlite3
|
||||
#cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3
|
||||
*/
|
||||
import "C"
|
||||
63
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
63
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build !sqlite_omit_load_extension
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#include <sqlite3-binding.h>
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
for _, extension := range extensions {
|
||||
cext := C.CString(extension)
|
||||
defer C.free(unsafe.Pointer(cext))
|
||||
rv = C.sqlite3_load_extension(c.db, cext, nil, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
clib := C.CString(lib)
|
||||
defer C.free(unsafe.Pointer(clib))
|
||||
centry := C.CString(entry)
|
||||
defer C.free(unsafe.Pointer(centry))
|
||||
|
||||
rv = C.sqlite3_load_extension(c.db, clib, centry, nil)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||
if rv != C.SQLITE_OK {
|
||||
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
23
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_omit_load_extension.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build sqlite_omit_load_extension
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||
return errors.New("Extensions have been disabled for static builds")
|
||||
}
|
||||
|
||||
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||
return errors.New("Extensions have been disabled for static builds")
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
1
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
@@ -9,6 +9,5 @@ package sqlite3
|
||||
/*
|
||||
#cgo CFLAGS: -I.
|
||||
#cgo linux LDFLAGS: -ldl
|
||||
#cgo LDFLAGS: -lpthread
|
||||
*/
|
||||
import "C"
|
||||
|
||||
947
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test.go
generated
vendored
947
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test.go
generated
vendored
@@ -1,947 +0,0 @@
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-sqlite3/sqlite3_test"
|
||||
)
|
||||
|
||||
func TempFilename() string {
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
return filepath.Join(os.TempDir(), "foo"+hex.EncodeToString(randBytes)+".db")
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(tempFilename); err != nil || stat.IsDir() {
|
||||
t.Error("Failed to create ./foo.db")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
stmt, err := db.Prepare("select id from foo where id = ?")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
|
||||
db.Close()
|
||||
_, err = stmt.Exec(1)
|
||||
if err == nil {
|
||||
t.Fatal("Failed to operate closed statement")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
affected, _ := res.RowsAffected()
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rows.Next()
|
||||
|
||||
var result int
|
||||
rows.Scan(&result)
|
||||
if result != 123 {
|
||||
t.Errorf("Fetched %q; expected %q", 123, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
expected, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
affected, _ := res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
res, err = db.Exec("update foo set id = 234")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to update record:", err)
|
||||
}
|
||||
lastId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
if expected != lastId {
|
||||
t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
|
||||
}
|
||||
affected, _ = res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Fatalf("Expected %d for affected rows, but %d:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rows.Next()
|
||||
|
||||
var result int
|
||||
rows.Scan(&result)
|
||||
if result != 234 {
|
||||
t.Errorf("Fetched %q; expected %q", 234, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("drop table foo")
|
||||
_, err = db.Exec("create table foo (id integer)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
res, err := db.Exec("insert into foo(id) values(123)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert record:", err)
|
||||
}
|
||||
expected, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
|
||||
}
|
||||
|
||||
res, err = db.Exec("delete from foo where id = 123")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to delete record:", err)
|
||||
}
|
||||
lastId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get LastInsertId:", err)
|
||||
}
|
||||
if expected != lastId {
|
||||
t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
|
||||
}
|
||||
affected, err = res.RowsAffected()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get RowsAffected:", err)
|
||||
}
|
||||
if affected != 1 {
|
||||
t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to select records:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
t.Error("Fetched row but expected not rows")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBooleanRoundtrip(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, value BOOL)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(1, ?)", true)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert true value:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id, value) VALUES(2, ?)", false)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert false value:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, value FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var value bool
|
||||
|
||||
if err := rows.Scan(&id, &value); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if id == 1 && !value {
|
||||
t.Error("Value for id 1 should be true, not false")
|
||||
|
||||
} else if id == 2 && value {
|
||||
t.Error("Value for id 2 should be false, not true")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts timeSTAMP, dt DATETIME)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
||||
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
|
||||
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
|
||||
tests := []struct {
|
||||
value interface{}
|
||||
expected time.Time
|
||||
}{
|
||||
{"nonsense", time.Time{}},
|
||||
{"0000-00-00 00:00:00", time.Time{}},
|
||||
{timestamp1, timestamp1},
|
||||
{timestamp1.Unix(), timestamp1},
|
||||
{timestamp1.UnixNano() / int64(time.Millisecond), timestamp1},
|
||||
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
|
||||
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1},
|
||||
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1},
|
||||
{timestamp2, timestamp2},
|
||||
{"2006-01-02 15:04:05.123456789", timestamp2},
|
||||
{"2006-01-02T15:04:05.123456789", timestamp2},
|
||||
{"2012-11-04", timestamp3},
|
||||
{"2012-11-04 00:00", timestamp3},
|
||||
{"2012-11-04 00:00:00", timestamp3},
|
||||
{"2012-11-04 00:00:00.000", timestamp3},
|
||||
{"2012-11-04T00:00", timestamp3},
|
||||
{"2012-11-04T00:00:00", timestamp3},
|
||||
{"2012-11-04T00:00:00.000", timestamp3},
|
||||
}
|
||||
for i := range tests {
|
||||
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert timestamp:", err)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
seen := 0
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ts, dt time.Time
|
||||
|
||||
if err := rows.Scan(&id, &ts, &dt); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
if id < 0 || id >= len(tests) {
|
||||
t.Error("Bad row id: ", id)
|
||||
continue
|
||||
}
|
||||
seen++
|
||||
if !tests[id].expected.Equal(ts) {
|
||||
t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
if !tests[id].expected.Equal(dt) {
|
||||
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
}
|
||||
|
||||
if seen != len(tests) {
|
||||
t.Errorf("Expected to see %d rows", len(tests))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolean(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, fbool BOOLEAN)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
bool1 := true
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(1, ?)", bool1)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert boolean:", err)
|
||||
}
|
||||
|
||||
bool2 := false
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(2, ?)", bool2)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert boolean:", err)
|
||||
}
|
||||
|
||||
bool3 := "nonsense"
|
||||
_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(3, ?)", bool3)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert nonsense:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, fbool FROM foo where fbool = ?", bool1)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
counter := 0
|
||||
|
||||
var id int
|
||||
var fbool bool
|
||||
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&id, &fbool); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
if counter != 1 {
|
||||
t.Fatalf("Expected 1 row but %v", counter)
|
||||
}
|
||||
|
||||
if id != 1 && fbool != true {
|
||||
t.Fatalf("Value for id 1 should be %v, not %v", bool1, fbool)
|
||||
}
|
||||
|
||||
rows, err = db.Query("SELECT id, fbool FROM foo where fbool = ?", bool2)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
counter = 0
|
||||
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&id, &fbool); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
if counter != 1 {
|
||||
t.Fatalf("Expected 1 row but %v", counter)
|
||||
}
|
||||
|
||||
if id != 2 && fbool != false {
|
||||
t.Fatalf("Value for id 2 should be %v, not %v", bool2, fbool)
|
||||
}
|
||||
|
||||
// make sure "nonsense" triggered an error
|
||||
rows, err = db.Query("SELECT id, fbool FROM foo where id=?;", 3)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
rows.Next()
|
||||
err = rows.Scan(&id, &fbool)
|
||||
if err == nil {
|
||||
t.Error("Expected error from \"nonsense\" bool")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO foo(id) VALUES(null)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
var id interface{}
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
if id != nil {
|
||||
t.Error("Expected nil but not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNull(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query("SELECT 3.141592")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
if err := rows.Scan(&v); err != nil {
|
||||
t.Fatal("Unable to scan results:", err)
|
||||
}
|
||||
f, ok := v.(float64)
|
||||
if !ok {
|
||||
t.Error("Expected float but not")
|
||||
}
|
||||
if f != 3.141592 {
|
||||
t.Error("Expected 3.141592 but not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransaction(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to begin transaction:", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO foo(id) VALUES(1)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
rows, err := tx.Query("SELECT id from foo")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to rollback transaction:", err)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Fatal("Unable to query results:", err)
|
||||
}
|
||||
|
||||
tx, err = db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to begin transaction:", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO foo(id) VALUES(1)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert null:", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to commit transaction:", err)
|
||||
}
|
||||
|
||||
rows, err = tx.Query("SELECT id from foo")
|
||||
if err == nil {
|
||||
t.Fatal("Expected failure to query")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWAL(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
if _, err = db.Exec("PRAGMA journal_mode=WAL;"); err != nil {
|
||||
t.Fatal("Failed to Exec PRAGMA journal_mode:", err)
|
||||
}
|
||||
if _, err = db.Exec("PRAGMA locking_mode=EXCLUSIVE;"); err != nil {
|
||||
t.Fatal("Failed to Exec PRAGMA locking_mode:", err)
|
||||
}
|
||||
if _, err = db.Exec("CREATE TABLE test (id SERIAL, user TEXT NOT NULL, name TEXT NOT NULL);"); err != nil {
|
||||
t.Fatal("Failed to Exec CREATE TABLE:", err)
|
||||
}
|
||||
if _, err = db.Exec("INSERT INTO test (user, name) VALUES ('user','name');"); err != nil {
|
||||
t.Fatal("Failed to Exec INSERT:", err)
|
||||
}
|
||||
|
||||
trans, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to Begin:", err)
|
||||
}
|
||||
s, err := trans.Prepare("INSERT INTO test (user, name) VALUES (?, ?);")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to Prepare:", err)
|
||||
}
|
||||
|
||||
var count int
|
||||
if err = trans.QueryRow("SELECT count(user) FROM test;").Scan(&count); err != nil {
|
||||
t.Fatal("Failed to QueryRow:", err)
|
||||
}
|
||||
if _, err = s.Exec("bbbb", "aaaa"); err != nil {
|
||||
t.Fatal("Failed to Exec prepared statement:", err)
|
||||
}
|
||||
if err = s.Close(); err != nil {
|
||||
t.Fatal("Failed to Close prepared statement:", err)
|
||||
}
|
||||
if err = trans.Commit(); err != nil {
|
||||
t.Fatal("Failed to Commit:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimezoneConversion(t *testing.T) {
|
||||
zones := []string{"UTC", "US/Central", "US/Pacific", "Local"}
|
||||
for _, tz := range zones {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+url.QueryEscape(tz))
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec("DROP TABLE foo")
|
||||
_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts TIMESTAMP, dt DATETIME)")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create table:", err)
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to load location:", err)
|
||||
}
|
||||
|
||||
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
||||
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
|
||||
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
|
||||
tests := []struct {
|
||||
value interface{}
|
||||
expected time.Time
|
||||
}{
|
||||
{"nonsense", time.Time{}.In(loc)},
|
||||
{"0000-00-00 00:00:00", time.Time{}.In(loc)},
|
||||
{timestamp1, timestamp1.In(loc)},
|
||||
{timestamp1.Unix(), timestamp1.In(loc)},
|
||||
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1.In(loc)},
|
||||
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1.In(loc)},
|
||||
{timestamp2, timestamp2.In(loc)},
|
||||
{"2006-01-02 15:04:05.123456789", timestamp2.In(loc)},
|
||||
{"2006-01-02T15:04:05.123456789", timestamp2.In(loc)},
|
||||
{"2012-11-04", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04 00:00:00.000", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00:00", timestamp3.In(loc)},
|
||||
{"2012-11-04T00:00:00.000", timestamp3.In(loc)},
|
||||
}
|
||||
for i := range tests {
|
||||
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to insert timestamp:", err)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := db.Query("SELECT id, ts, dt FROM foo ORDER BY id ASC")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to query foo table:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
seen := 0
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ts, dt time.Time
|
||||
|
||||
if err := rows.Scan(&id, &ts, &dt); err != nil {
|
||||
t.Error("Unable to scan results:", err)
|
||||
continue
|
||||
}
|
||||
if id < 0 || id >= len(tests) {
|
||||
t.Error("Bad row id: ", id)
|
||||
continue
|
||||
}
|
||||
seen++
|
||||
if !tests[id].expected.Equal(ts) {
|
||||
t.Errorf("Timestamp value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, ts)
|
||||
}
|
||||
if !tests[id].expected.Equal(dt) {
|
||||
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
|
||||
}
|
||||
if tests[id].expected.Location().String() != ts.Location().String() {
|
||||
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), ts.Location().String())
|
||||
}
|
||||
if tests[id].expected.Location().String() != dt.Location().String() {
|
||||
t.Errorf("Location for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected.Location().String(), dt.Location().String())
|
||||
}
|
||||
}
|
||||
|
||||
if seen != len(tests) {
|
||||
t.Errorf("Expected to see %d rows", len(tests))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
db, err := sql.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
sqlite3_test.RunTests(t, db, sqlite3_test.SQLITE)
|
||||
}
|
||||
|
||||
// TODO: Execer & Queryer currently disabled
|
||||
// https://github.com/mattn/go-sqlite3/issues/82
|
||||
func TestExecer(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer); -- one comment
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?); -- another comment
|
||||
`, 1, 2, 3)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Exec:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryer(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer);
|
||||
`)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
|
||||
rows, err := db.Query(`
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
insert into foo(id) values(?);
|
||||
select id from foo order by id;
|
||||
`, 3, 2, 1)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
n := 1
|
||||
if rows != nil {
|
||||
for rows.Next() {
|
||||
var id int
|
||||
err = rows.Scan(&id)
|
||||
if err != nil {
|
||||
t.Error("Failed to db.Query:", err)
|
||||
}
|
||||
if id != n {
|
||||
t.Error("Failed to db.Query: not matched results")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStress(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
db.Exec("CREATE TABLE foo (id int);")
|
||||
db.Exec("INSERT INTO foo VALUES(1);")
|
||||
db.Exec("INSERT INTO foo VALUES(2);")
|
||||
db.Close()
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
for j := 0; j < 3; j++ {
|
||||
rows, err := db.Query("select * from foo where id=1;")
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
for rows.Next() {
|
||||
var i int
|
||||
if err := rows.Scan(&i); err != nil {
|
||||
t.Errorf("Scan failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Errorf("Post-scan failed: %v\n", err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeLocal(t *testing.T) {
|
||||
zone := "Asia/Tokyo"
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename+"?_loc="+zone)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
db.Exec("CREATE TABLE foo (dt datetime);")
|
||||
db.Exec("INSERT INTO foo VALUES('2015-03-05 15:16:17');")
|
||||
|
||||
row := db.QueryRow("select * from foo")
|
||||
var d time.Time
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.Hour() == 15 || !strings.Contains(d.String(), "JST") {
|
||||
t.Fatal("Result should have timezone", d)
|
||||
}
|
||||
db.Close()
|
||||
|
||||
db, err = sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
row = db.QueryRow("select * from foo")
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.UTC().Hour() != 15 || !strings.Contains(d.String(), "UTC") {
|
||||
t.Fatalf("Result should not have timezone %v %v", zone, d.String())
|
||||
}
|
||||
|
||||
_, err = db.Exec("DELETE FROM foo")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to delete table:", err)
|
||||
}
|
||||
dt, err := time.Parse("2006/1/2 15/4/5 -0700 MST", "2015/3/5 15/16/17 +0900 JST")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to parse datetime:", err)
|
||||
}
|
||||
db.Exec("INSERT INTO foo VALUES(?);", dt)
|
||||
|
||||
db.Close()
|
||||
db, err = sql.Open("sqlite3", tempFilename+"?_loc="+zone)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
|
||||
row = db.QueryRow("select * from foo")
|
||||
err = row.Scan(&d)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to scan datetime:", err)
|
||||
}
|
||||
if d.Hour() != 15 || !strings.Contains(d.String(), "JST") {
|
||||
t.Fatalf("Result should have timezone %v %v", zone, d.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
s, n, id := Version()
|
||||
if s == "" || n == 0 || id == "" {
|
||||
t.Errorf("Version failed %q, %d, %q\n", s, n, id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumberNamedParams(t *testing.T) {
|
||||
tempFilename := TempFilename()
|
||||
db, err := sql.Open("sqlite3", tempFilename)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open database:", err)
|
||||
}
|
||||
defer os.Remove(tempFilename)
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`
|
||||
create table foo (id integer, name text, extra text);
|
||||
`)
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Query:", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(`insert into foo(id, name, extra) values($1, $2, $2)`, 1, "foo")
|
||||
if err != nil {
|
||||
t.Error("Failed to call db.Exec:", err)
|
||||
}
|
||||
|
||||
row := db.QueryRow(`select id, extra from foo where id = $1 and extra = $2`, 1, "foo")
|
||||
if row == nil {
|
||||
t.Error("Failed to call db.QueryRow")
|
||||
}
|
||||
var id int
|
||||
var extra string
|
||||
err = row.Scan(&id, &extra)
|
||||
if err != nil {
|
||||
t.Error("Failed to db.Scan:", err)
|
||||
}
|
||||
if id != 1 || extra != "foo" {
|
||||
t.Error("Failed to db.QueryRow: not matched results")
|
||||
}
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go
generated
vendored
17
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go
generated
vendored
@@ -275,12 +275,11 @@ func TestPreparedStmt(t *testing.T) {
|
||||
}
|
||||
|
||||
const nRuns = 10
|
||||
ch := make(chan bool)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < nRuns; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
ch <- true
|
||||
}()
|
||||
defer wg.Done()
|
||||
for j := 0; j < 10; j++ {
|
||||
count := 0
|
||||
if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows {
|
||||
@@ -294,9 +293,7 @@ func TestPreparedStmt(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
for i := 0; i < nRuns; i++ {
|
||||
<-ch
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Benchmarks need to use panic() since b.Error errors are lost when
|
||||
@@ -318,7 +315,7 @@ func BenchmarkQuery(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -331,7 +328,7 @@ func BenchmarkParams(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -350,7 +347,7 @@ func BenchmarkStmt(b *testing.B) {
|
||||
var i int
|
||||
var f float64
|
||||
var s string
|
||||
// var t time.Time
|
||||
// var t time.Time
|
||||
if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
2
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
2
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
@@ -8,7 +8,7 @@ package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
|
||||
#cgo windows,386 CFLAGS: -D_localtime32=localtime
|
||||
#cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T
|
||||
#cgo LDFLAGS: -lmingwex -lmingw32
|
||||
*/
|
||||
import "C"
|
||||
|
||||
65
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
65
Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
@@ -28,7 +28,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each others' shared
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
@@ -250,11 +250,40 @@ struct sqlite3_api_routines {
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*vsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
};
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected throught the global sqlite3_api structure.
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
@@ -263,7 +292,7 @@ struct sqlite3_api_routines {
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#ifndef SQLITE_CORE
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
@@ -390,6 +419,7 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
@@ -467,9 +497,34 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
#endif /* SQLITE_CORE */
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
|
||||
17
Makefile
Normal file
17
Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
all: deps build
|
||||
|
||||
deps:
|
||||
go run build.go setup
|
||||
godep restore
|
||||
npm install
|
||||
|
||||
build:
|
||||
go run build.go build
|
||||
npm run build
|
||||
|
||||
test:
|
||||
godep go test -v ./pkg/...
|
||||
npm test
|
||||
|
||||
run:
|
||||
./bin/grafana-server
|
||||
29
README.md
29
README.md
@@ -16,6 +16,7 @@ Graphite, Elasticsearch, OpenTSDB, Prometheus and InfluxDB.
|
||||
- [What's New in Grafana 2.0](http://docs.grafana.org/guides/whats-new-in-v2/)
|
||||
- [What's New in Grafana 2.1](http://docs.grafana.org/guides/whats-new-in-v2-1/)
|
||||
- [What's New in Grafana 2.5](http://docs.grafana.org/guides/whats-new-in-v2-5/)
|
||||
- [What's New in Grafana 3.0](http://docs.grafana.org/guides/whats-new-in-v3/)
|
||||
|
||||
## Features
|
||||
### Graphite Target Editor
|
||||
@@ -78,7 +79,7 @@ the latest master builds [here](http://grafana.org/download/builds)
|
||||
### Dependencies
|
||||
|
||||
- Go 1.5
|
||||
- NodeJS
|
||||
- NodeJS v4+
|
||||
- [Godep](https://github.com/tools/godep)
|
||||
|
||||
### Get Code
|
||||
@@ -87,8 +88,19 @@ the latest master builds [here](http://grafana.org/download/builds)
|
||||
go get github.com/grafana/grafana
|
||||
```
|
||||
|
||||
Since imports of dependencies use the absolute path github.com/grafana/grafana within the $GOPATH,
|
||||
you will need to put your version of the code in $GOPATH/src/github.com/grafana/grafana to be able
|
||||
to develop and build grafana on a cloned repository. To do so, you can clone your forked repository
|
||||
directly to $GOPATH/src/github.com/grafana or you can create a symbolic link from your version
|
||||
of the code to $GOPATH/src/github.com/grafana/grafana. The last options makes it possible to change
|
||||
easily the grafana repository you want to build.
|
||||
```bash
|
||||
go get github.com/*your_account*/grafana
|
||||
mkdir $GOPATH/src/github.com/grafana
|
||||
ln -s github.com/*your_account*/grafana $GOPATH/src/github.com/grafana/grafana
|
||||
```
|
||||
|
||||
### Building the backend
|
||||
Replace X.Y.Z by actual version number.
|
||||
```bash
|
||||
cd $GOPATH/src/github.com/grafana/grafana
|
||||
go run build.go setup (only needed once to install godep)
|
||||
@@ -98,13 +110,19 @@ go run build.go build
|
||||
|
||||
### Building frontend assets
|
||||
|
||||
To build less to css for the frontend you will need a recent version of of node (v0.12.0),
|
||||
To build less to css for the frontend you will need a recent version of of **node (v4+)**,
|
||||
npm (v2.5.0) and grunt (v0.4.5). Run the following:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm install -g grunt-cli
|
||||
grunt
|
||||
npm run build
|
||||
```
|
||||
|
||||
To build the frontend assets only on changes:
|
||||
|
||||
```bash
|
||||
sudo npm install -g grunt-cli # to do only once to install grunt command line interface
|
||||
grunt watch
|
||||
```
|
||||
|
||||
### Recompile backend on source change
|
||||
@@ -145,4 +163,3 @@ please [sign the CLA](http://docs.grafana.org/project/cla/)
|
||||
|
||||
Grafana is distributed under Apache 2.0 License.
|
||||
Work in progress Grafana 2.0 (with included Grafana backend)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ install:
|
||||
- npm install
|
||||
- npm install -g grunt-cli
|
||||
# install gcc (needed for sqlite3)
|
||||
- choco install -y mingw
|
||||
- choco install -y --limit-output mingw
|
||||
- set PATH=C:\tools\mingw64\bin;%PATH%
|
||||
- echo %PATH%
|
||||
- echo %GOPATH%
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "~2.1.4",
|
||||
"jquery": "~2.2.4",
|
||||
"angular": "~1.5.3",
|
||||
"angular-route": "~1.5.3",
|
||||
"angular-mocks": "~1.5.3",
|
||||
|
||||
10
build.go
10
build.go
@@ -132,12 +132,10 @@ func readVersionFromPackageJson() {
|
||||
if len(parts) > 1 {
|
||||
linuxPackageVersion = parts[0]
|
||||
linuxPackageIteration = parts[1]
|
||||
if linuxPackageIteration != "" {
|
||||
// add timestamp to iteration
|
||||
linuxPackageIteration = fmt.Sprintf("%s%v", linuxPackageIteration, time.Now().Unix())
|
||||
}
|
||||
log.Println(fmt.Sprintf("teration %v", linuxPackageIteration))
|
||||
}
|
||||
|
||||
// add timestamp to iteration
|
||||
linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
|
||||
}
|
||||
|
||||
type linuxPackageOptions struct {
|
||||
@@ -306,7 +304,7 @@ func ChangeWorkingDir(dir string) {
|
||||
}
|
||||
|
||||
func grunt(params ...string) {
|
||||
runPrint("./node_modules/grunt-cli/bin/grunt", params...)
|
||||
runPrint("./node_modules/.bin/grunt", params...)
|
||||
}
|
||||
|
||||
func setup() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
machine:
|
||||
node:
|
||||
version: 4.0
|
||||
version: 5.11.1
|
||||
environment:
|
||||
GOPATH: "/home/ubuntu/.go_workspace"
|
||||
ORG_PATH: "github.com/grafana"
|
||||
@@ -25,12 +25,12 @@ test:
|
||||
# Go test
|
||||
- godep go test -v ./pkg/...
|
||||
# js tests
|
||||
- ./node_modules/grunt-cli/bin/grunt test
|
||||
- npm test
|
||||
- npm run coveralls
|
||||
|
||||
deployment:
|
||||
master:
|
||||
branch: master
|
||||
owner: grafana
|
||||
commands:
|
||||
commands:
|
||||
- ./trigger_grafana_packer.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
# possible values : production, development
|
||||
app_mode = production
|
||||
|
||||
# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
|
||||
instance_name = ${HOSTNAME}
|
||||
|
||||
#################################### Paths ####################################
|
||||
[paths]
|
||||
# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
|
||||
@@ -143,7 +146,7 @@ cookie_remember_name = grafana_remember
|
||||
# disable gravatar profile images
|
||||
disable_gravatar = false
|
||||
|
||||
# data source proxy whitelist (ip_or_domain:port seperated by spaces)
|
||||
# data source proxy whitelist (ip_or_domain:port separated by spaces)
|
||||
data_source_proxy_whitelist =
|
||||
|
||||
[snapshots]
|
||||
@@ -172,6 +175,9 @@ verify_email_enabled = false
|
||||
# Background text for the user field on the login page
|
||||
login_hint = email or username
|
||||
|
||||
# Default UI theme ("dark" or "light")
|
||||
default_theme = dark
|
||||
|
||||
#################################### Anonymous Auth ##########################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -241,25 +247,27 @@ templates_pattern = emails/*.html
|
||||
|
||||
#################################### Logging ##########################
|
||||
[log]
|
||||
# Either "console", "file", default is "console"
|
||||
# Use comma to separate multiple modes, e.g. "console, file"
|
||||
# Either "console", "file", "syslog". Default is console and file
|
||||
# Use space to separate multiple modes, e.g. "console file"
|
||||
mode = console, file
|
||||
|
||||
# Buffer length of channel, keep it as it is if you don't know what it is.
|
||||
buffer_len = 10000
|
||||
|
||||
# Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
|
||||
level = Info
|
||||
# Either "debug", "info", "warn", "error", "critical", default is "info"
|
||||
level = info
|
||||
|
||||
# For "console" mode only
|
||||
[log.console]
|
||||
level =
|
||||
# Set formatting to "false" to disable color formatting of console logs
|
||||
formatting = false
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
format = console
|
||||
|
||||
# For "file" mode only
|
||||
[log.file]
|
||||
level =
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
format = text
|
||||
|
||||
# This enables automated log rotate(switch of following options), default is true
|
||||
log_rotate = true
|
||||
|
||||
@@ -267,7 +275,7 @@ log_rotate = true
|
||||
max_lines = 1000000
|
||||
|
||||
# Max size shift of single file, default is 28 means 1 << 28, 256MB
|
||||
max_lines_shift = 28
|
||||
max_size_shift = 28
|
||||
|
||||
# Segment log daily, default is true
|
||||
daily_rotate = true
|
||||
@@ -277,6 +285,10 @@ max_days = 7
|
||||
|
||||
[log.syslog]
|
||||
level =
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
format = text
|
||||
|
||||
# Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used.
|
||||
network =
|
||||
address =
|
||||
@@ -287,7 +299,8 @@ facility =
|
||||
# Syslog tag. By default, the process' argv[0] is used.
|
||||
tag =
|
||||
|
||||
#################################### AMPQ Event Publisher ##########################
|
||||
|
||||
#################################### AMQP Event Publisher ##########################
|
||||
[event_publisher]
|
||||
enabled = false
|
||||
rabbitmq_url = amqp://localhost/
|
||||
@@ -332,3 +345,17 @@ global_api_key = -1
|
||||
|
||||
# global limit on number of logged in users.
|
||||
global_session = -1
|
||||
|
||||
#################################### Internal Grafana Metrics ##########################
|
||||
# Metrics available at HTTP API Url /api/metrics
|
||||
[metrics]
|
||||
enabled = true
|
||||
interval_seconds = 60
|
||||
|
||||
# Send internal Grafana metrics to graphite
|
||||
; [metrics.graphite]
|
||||
; address = localhost:2003
|
||||
; prefix = prod.grafana.%(instance_name)s.
|
||||
|
||||
[grafana_net]
|
||||
url = https://grafana.net
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
# possible values : production, development
|
||||
; app_mode = production
|
||||
|
||||
# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
|
||||
; instance_name = ${HOSTNAME}
|
||||
|
||||
#################################### Paths ####################################
|
||||
[paths]
|
||||
# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
|
||||
@@ -129,7 +132,7 @@ check_for_updates = true
|
||||
# disable gravatar profile images
|
||||
;disable_gravatar = false
|
||||
|
||||
# data source proxy whitelist (ip_or_domain:port seperated by spaces)
|
||||
# data source proxy whitelist (ip_or_domain:port separated by spaces)
|
||||
;data_source_proxy_whitelist =
|
||||
|
||||
[snapshots]
|
||||
@@ -155,6 +158,9 @@ check_for_updates = true
|
||||
# Background text for the user field on the login page
|
||||
;login_hint = email or username
|
||||
|
||||
# Default UI theme ("dark" or "light")
|
||||
;default_theme = dark
|
||||
|
||||
#################################### Anonymous Auth ##########################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -223,23 +229,27 @@ check_for_updates = true
|
||||
|
||||
#################################### Logging ##########################
|
||||
[log]
|
||||
# Either "console", "file", default is "console"
|
||||
# Use comma to separate multiple modes, e.g. "console, file"
|
||||
# Either "console", "file", "syslog". Default is console and file
|
||||
# Use space to separate multiple modes, e.g. "console file"
|
||||
;mode = console, file
|
||||
|
||||
# Buffer length of channel, keep it as it is if you don't know what it is.
|
||||
;buffer_len = 10000
|
||||
|
||||
# Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
|
||||
;level = Info
|
||||
# Either "trace", "debug", "info", "warn", "error", "critical", default is "info"
|
||||
;level = info
|
||||
|
||||
# For "console" mode only
|
||||
[log.console]
|
||||
;level =
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
;format = console
|
||||
|
||||
# For "file" mode only
|
||||
[log.file]
|
||||
;level =
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
;format = text
|
||||
|
||||
# This enables automated log rotate(switch of following options), default is true
|
||||
;log_rotate = true
|
||||
|
||||
@@ -247,7 +257,7 @@ check_for_updates = true
|
||||
;max_lines = 1000000
|
||||
|
||||
# Max size shift of single file, default is 28 means 1 << 28, 256MB
|
||||
;max_lines_shift = 28
|
||||
;max_size_shift = 28
|
||||
|
||||
# Segment log daily, default is true
|
||||
;daily_rotate = true
|
||||
@@ -255,7 +265,24 @@ check_for_updates = true
|
||||
# Expired days of log file(delete after max days), default is 7
|
||||
;max_days = 7
|
||||
|
||||
#################################### AMPQ Event Publisher ##########################
|
||||
[log.syslog]
|
||||
;level =
|
||||
|
||||
# log line format, valid options are text, console and json
|
||||
;format = text
|
||||
|
||||
# Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used.
|
||||
;network =
|
||||
;address =
|
||||
|
||||
# Syslog facility. user, daemon and local0 through local7 are valid.
|
||||
;facility =
|
||||
|
||||
# Syslog tag. By default, the process' argv[0] is used.
|
||||
;tag =
|
||||
|
||||
|
||||
#################################### AMQP Event Publisher ##########################
|
||||
[event_publisher]
|
||||
;enabled = false
|
||||
;rabbitmq_url = amqp://localhost/
|
||||
@@ -266,5 +293,21 @@ check_for_updates = true
|
||||
;enabled = false
|
||||
;path = /var/lib/grafana/dashboards
|
||||
|
||||
#################################### Internal Grafana Metrics ##########################
|
||||
# Metrics available at HTTP API Url /api/metrics
|
||||
[metrics]
|
||||
# Disable / Enable internal metrics
|
||||
;enabled = true
|
||||
|
||||
# Publish interval
|
||||
;interval_seconds = 10
|
||||
|
||||
# Send internal metrics to Graphite
|
||||
; [metrics.graphite]
|
||||
; address = localhost:2003
|
||||
; prefix = prod.grafana.%(instance_name)s.
|
||||
|
||||
#################################### Internal Grafana Metrics ##########################
|
||||
# Url used to to import dashboards directly from Grafana.net
|
||||
[grafana_net]
|
||||
url = https://grafana.net
|
||||
|
||||
16
docker/blocks/collectd/Dockerfile
Normal file
16
docker/blocks/collectd/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM ubuntu:xenial
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y install collectd curl python-pip
|
||||
|
||||
# add a fake mtab for host disk stats
|
||||
ADD etc_mtab /etc/mtab
|
||||
|
||||
ADD collectd.conf.tpl /etc/collectd/collectd.conf.tpl
|
||||
|
||||
RUN pip install envtpl
|
||||
ADD start_container /usr/bin/start_container
|
||||
RUN chmod +x /usr/bin/start_container
|
||||
CMD start_container
|
||||
37
docker/blocks/collectd/README.md
Normal file
37
docker/blocks/collectd/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
collectd-write-graphite
|
||||
=======================
|
||||
|
||||
Basic collectd-based server monitoring. Sends stats to Graphite.
|
||||
|
||||
Collectd metrics:
|
||||
|
||||
* CPU used/free/idle/etc
|
||||
* Free disk (via mounting hosts '/' into container, eg: -v /:/hostfs:ro)
|
||||
* Disk performance
|
||||
* Load average
|
||||
* Memory used/free/etc
|
||||
* Uptime
|
||||
* Network interface
|
||||
* Swap
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
|
||||
* `HOST_NAME`
|
||||
- Will be sent to Graphite
|
||||
- Required
|
||||
* `GRAPHITE_HOST`
|
||||
- Graphite IP or hostname
|
||||
- Required
|
||||
* `GRAPHITE_PORT`
|
||||
- Graphite port
|
||||
- Optional, defaults to 2003
|
||||
* `GRAPHITE_PREFIX`
|
||||
- Graphite prefix
|
||||
- Optional, defaults to collectd.
|
||||
* `REPORT_BY_CPU`
|
||||
- Report per-CPU metrics if true, global sum of CPU metrics if false (details: [collectd.conf man page](https://collectd.org/documentation/manpages/collectd.conf.5.shtml#plugin_cpu))
|
||||
- Optional, defaults to false.
|
||||
* `COLLECT_INTERVAL`
|
||||
- Collection interval and thus resolution of metrics
|
||||
- Optional, defaults to 10
|
||||
106
docker/blocks/collectd/collectd.conf.tpl
Normal file
106
docker/blocks/collectd/collectd.conf.tpl
Normal file
@@ -0,0 +1,106 @@
|
||||
Hostname "{{ HOST_NAME }}"
|
||||
|
||||
FQDNLookup false
|
||||
Interval {{ COLLECT_INTERVAL | default("10") }}
|
||||
Timeout 2
|
||||
ReadThreads 5
|
||||
|
||||
LoadPlugin cpu
|
||||
LoadPlugin df
|
||||
LoadPlugin load
|
||||
LoadPlugin memory
|
||||
LoadPlugin disk
|
||||
LoadPlugin interface
|
||||
LoadPlugin uptime
|
||||
LoadPlugin swap
|
||||
LoadPlugin write_graphite
|
||||
LoadPlugin processes
|
||||
LoadPlugin aggregation
|
||||
LoadPlugin match_regex
|
||||
# LoadPlugin memcached
|
||||
|
||||
<Plugin df>
|
||||
# expose host's mounts into container using -v /:/host:ro (location inside container does not matter much)
|
||||
# ignore rootfs; else, the root file-system would appear twice, causing
|
||||
# one of the updates to fail and spam the log
|
||||
FSType rootfs
|
||||
# ignore the usual virtual / temporary file-systems
|
||||
FSType sysfs
|
||||
FSType proc
|
||||
FSType devtmpfs
|
||||
FSType devpts
|
||||
FSType tmpfs
|
||||
FSType fusectl
|
||||
FSType cgroup
|
||||
FSType overlay
|
||||
FSType debugfs
|
||||
FSType pstore
|
||||
FSType securityfs
|
||||
FSType hugetlbfs
|
||||
FSType squashfs
|
||||
FSType mqueue
|
||||
MountPoint "/etc/resolv.conf"
|
||||
MountPoint "/etc/hostname"
|
||||
MountPoint "/etc/hosts"
|
||||
IgnoreSelected true
|
||||
ReportByDevice false
|
||||
ReportReserved true
|
||||
ReportInodes true
|
||||
ValuesAbsolute true
|
||||
ValuesPercentage true
|
||||
ReportInodes true
|
||||
</Plugin>
|
||||
|
||||
<Plugin "disk">
|
||||
Disk "/^[hs]d[a-z]/"
|
||||
IgnoreSelected false
|
||||
</Plugin>
|
||||
|
||||
<Plugin "aggregation">
|
||||
<Aggregation>
|
||||
Plugin "cpu"
|
||||
Type "cpu"
|
||||
GroupBy "Host"
|
||||
GroupBy "TypeInstance"
|
||||
CalculateAverage true
|
||||
</Aggregation>
|
||||
</Plugin>
|
||||
|
||||
<Plugin interface>
|
||||
Interface "lo"
|
||||
Interface "/^veth.*/"
|
||||
Interface "/^docker.*/"
|
||||
IgnoreSelected true
|
||||
</Plugin>
|
||||
|
||||
# <Plugin "memcached">
|
||||
# Host "memcached"
|
||||
# Port "11211"
|
||||
# </Plugin>
|
||||
|
||||
<Chain "PostCache">
|
||||
<Rule>
|
||||
<Match regex>
|
||||
Plugin "^cpu$"
|
||||
PluginInstance "^[0-9]+$"
|
||||
</Match>
|
||||
<Target write>
|
||||
Plugin "aggregation"
|
||||
</Target>
|
||||
Target stop
|
||||
</Rule>
|
||||
Target "write"
|
||||
</Chain>
|
||||
|
||||
<Plugin "write_graphite">
|
||||
<Carbon>
|
||||
Host "{{ GRAPHITE_HOST }}"
|
||||
Port "{{ GRAPHITE_PORT | default("2003") }}"
|
||||
Prefix "{{ GRAPHITE_PREFIX | default("collectd.") }}"
|
||||
EscapeCharacter "_"
|
||||
SeparateInstances true
|
||||
StoreRates true
|
||||
AlwaysAppendDS false
|
||||
</Carbon>
|
||||
</Plugin>
|
||||
|
||||
1
docker/blocks/collectd/etc_mtab
Normal file
1
docker/blocks/collectd/etc_mtab
Normal file
@@ -0,0 +1 @@
|
||||
hostfs /.dockerinit ext4 ro,relatime,user_xattr,barrier=1,data=ordered 0 0
|
||||
12
docker/blocks/collectd/fig
Normal file
12
docker/blocks/collectd/fig
Normal file
@@ -0,0 +1,12 @@
|
||||
collectd:
|
||||
build: blocks/collectd
|
||||
environment:
|
||||
HOST_NAME: myserver
|
||||
GRAPHITE_HOST: graphite
|
||||
GRAPHITE_PORT: 2003
|
||||
GRAPHITE_PREFIX: collectd.
|
||||
REPORT_BY_CPU: 'false'
|
||||
COLLECT_INTERVAL: 10
|
||||
links:
|
||||
- graphite
|
||||
- memcached
|
||||
5
docker/blocks/collectd/start_container
Normal file
5
docker/blocks/collectd/start_container
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
envtpl /etc/collectd/collectd.conf.tpl
|
||||
|
||||
collectd -f
|
||||
@@ -8,3 +8,10 @@ graphite:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
|
||||
fake-graphite-data:
|
||||
image: grafana/fake-data-gen
|
||||
net: bridge
|
||||
environment:
|
||||
FD_DATASOURCE: graphite
|
||||
FD_PORT: 2003
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
influxdb:
|
||||
image: tutum/influxdb:latest
|
||||
image: tutum/influxdb:0.12
|
||||
ports:
|
||||
- "2004:2004"
|
||||
- "8083:8083"
|
||||
- "8086:8086"
|
||||
|
||||
fake-influxdb-data:
|
||||
image: grafana/fake-data-gen
|
||||
net: bridge
|
||||
environment:
|
||||
FD_DATASOURCE: influxdb
|
||||
FD_PORT: 8086
|
||||
|
||||
|
||||
5
docker/blocks/memcached/fig
Normal file
5
docker/blocks/memcached/fig
Normal file
@@ -0,0 +1,5 @@
|
||||
memcached:
|
||||
image: memcached:latest
|
||||
ports:
|
||||
- "11211:11211"
|
||||
|
||||
@@ -2,4 +2,10 @@ opentsdb:
|
||||
image: opower/opentsdb:latest
|
||||
ports:
|
||||
- "4242:4242"
|
||||
|
||||
|
||||
fake-opentsdb-data:
|
||||
image: grafana/fake-data-gen
|
||||
net: bridge
|
||||
environment:
|
||||
FD_DATASOURCE: opentsdb
|
||||
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
prometheus:
|
||||
build: blocks/prometheus
|
||||
net: bridge
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- /var/docker/prometheus:/prometheus-data
|
||||
|
||||
node_exporter:
|
||||
image: prom/node-exporter
|
||||
net: bridge
|
||||
ports:
|
||||
- "9100:9100"
|
||||
|
||||
fake-prometheus-data:
|
||||
image: grafana/fake-data-gen
|
||||
net: bridge
|
||||
ports:
|
||||
- "9091:9091"
|
||||
environment:
|
||||
FD_DATASOURCE: prom
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ scrape_configs:
|
||||
# scheme defaults to 'http'.
|
||||
|
||||
target_groups:
|
||||
- targets: ['localhost:9090', '172.17.0.1:9091']
|
||||
- targets: ['localhost:9090', '172.17.0.1:9091', '172.17.0.1:9100', '172.17.0.1:9150']
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
To build the docs locally, you need to have docker installed. The docs are built using a custom [docker](https://www.docker.com/)
|
||||
image and [mkdocs](http://www.mkdocs.org/).
|
||||
# Building The Docs
|
||||
|
||||
Build the `grafana/docs-base:latest` image:
|
||||
To build the docs locally, you need to have docker installed. The
|
||||
docs are built using a custom [docker](https://www.docker.com/) image
|
||||
and the [mkdocs](http://www.mkdocs.org/) tool.
|
||||
|
||||
**Prepare the Docker Image**:
|
||||
|
||||
Build the `grafana/docs-base:latest` image. Run these commands in the
|
||||
same directory this file is in. **Note** that you may require ``sudo``
|
||||
when running ``make docs-build`` depending on how your system's docker
|
||||
service is configured):
|
||||
|
||||
```
|
||||
$ git clone https://github.com/grafana/docs-base
|
||||
@@ -9,10 +17,45 @@ $ cd docs-base
|
||||
$ make docs-build
|
||||
```
|
||||
|
||||
To build the docs:
|
||||
**Build the Documentation**:
|
||||
|
||||
Now that the docker image has been prepared we can build the
|
||||
docs. Switch your working directory back to the directory this file
|
||||
(README.md) is in and run (possibly with ``sudo``):
|
||||
|
||||
```
|
||||
$ cd docs
|
||||
$ make docs
|
||||
```
|
||||
|
||||
This command will not return control of the shell to the user. Instead
|
||||
the command is now running a new docker container built from the image
|
||||
we created in the previous step.
|
||||
|
||||
Open [localhost:8180](http://localhost:8180) to view the docs.
|
||||
|
||||
**Note** that after running ``make docs`` you may notice a message
|
||||
like this in the console output
|
||||
|
||||
> Running at: http://0.0.0.0:8000/
|
||||
|
||||
This is misleading. That is **not** the port the documentation is
|
||||
served from. You must browse to port **8180** to view the new
|
||||
documentation.
|
||||
|
||||
|
||||
# Adding a New Page
|
||||
|
||||
Adding a new page requires updating the ``mkdocs.yml`` file which is
|
||||
located in this directory.
|
||||
|
||||
For example, if you are adding documentation for a new HTTP API called
|
||||
``preferences`` you would:
|
||||
|
||||
1. Create the file ``docs/sources/http_api/preferences.md``
|
||||
1. Add a reference to it in ``docs/sources/http_api/overview.md``
|
||||
1. Update the list under the **pages** key in the ``docs/mkdocs.yml`` file with a reference to your new page:
|
||||
|
||||
|
||||
```yaml
|
||||
- ['http_api/preferences.md', 'API', 'Preferences API']
|
||||
```
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.0
|
||||
3.1.0
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
site_name: Grafana Documentation
|
||||
#site_url: http://docs.grafana.com/
|
||||
site_url: /
|
||||
site_description: Documentation for Grafana, The Graphite and Influxdb dashboard and graph composer
|
||||
site_favicon: img/fav32.png
|
||||
@@ -46,6 +45,8 @@ pages:
|
||||
|
||||
- ['guides/basic_concepts.md', 'User Guides', 'Basic Concepts']
|
||||
- ['guides/gettingstarted.md', 'User Guides', 'Getting Started']
|
||||
- ['guides/whats-new-in-v3-1.md', 'User Guides', "What's New in Grafana v3.1"]
|
||||
- ['guides/whats-new-in-v3.md', 'User Guides', "What's New in Grafana v3.0"]
|
||||
- ['guides/whats-new-in-v2-6.md', 'User Guides', "What's New in Grafana v2.6"]
|
||||
- ['guides/whats-new-in-v2-5.md', 'User Guides', "What's New in Grafana v2.5"]
|
||||
- ['guides/whats-new-in-v2-1.md', 'User Guides', "What's New in Grafana v2.1"]
|
||||
@@ -84,6 +85,7 @@ pages:
|
||||
- ['http_api/user.md', 'API', 'User API']
|
||||
- ['http_api/admin.md', 'API', 'Admin API']
|
||||
- ['http_api/snapshot.md', 'API', 'Snapshot API']
|
||||
- ['http_api/preferences.md', 'API', 'Preferences API']
|
||||
- ['http_api/other.md', 'API', 'Other API']
|
||||
|
||||
- ['plugins/index.md', 'Plugins', 'Overview']
|
||||
|
||||
@@ -26,6 +26,8 @@ Name | The data source name, important that this is the same as in Grafana v1.x
|
||||
Default | Default data source means that it will be pre-selected for new panels.
|
||||
Credentials profile name | Specify the name of the profile to use (if you use `~/aws/credentials` file), leave blank for default. This option was introduced in Grafana 2.5.1
|
||||
Default Region | Used in query editor to set region (can be changed on per query basis)
|
||||
Custom Metrics namespace | Specify the CloudWatch namespace of Custom metrics
|
||||
Assume Role Arn | Specify the ARN of the role to assume
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -95,8 +97,8 @@ Example `ec2_instance_attribute()` query
|
||||
|
||||
## Cost
|
||||
|
||||
It's worth to mention that Amazon will charge you for CloudWatch API usage. CloudWatch costs
|
||||
$0.01 per 1,000 GetMetricStatistics or ListMetrics requests. For each query Grafana will
|
||||
Amazon provides 1 million CloudWatch API requests each month at no additional charge. Past this,
|
||||
it costs $0.01 per 1,000 GetMetricStatistics or ListMetrics requests. For each query Grafana will
|
||||
issue a GetMetricStatistics request and every time you pick a dimension in the query editor
|
||||
Grafana will issue a ListMetrics request.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Access | Proxy = access via Grafana backend, Direct = access directory from brow
|
||||
## Query editor
|
||||
Open a graph in edit mode by click the title.
|
||||
|
||||

|
||||

|
||||
|
||||
For details on KairosDB metric queries checkout the official.
|
||||
- [Query Metrics - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/QueryMetrics.html).
|
||||
|
||||
@@ -7,10 +7,10 @@ page_keywords: grafana, opentsdb, documentation
|
||||
# OpenTSDB Guide
|
||||
The newest release of Grafana adds additional functionality when using an OpenTSDB Data source.
|
||||
|
||||

|
||||

|
||||
|
||||
1. Open the side menu by clicking the the Grafana icon in the top header.
|
||||
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
|
||||
1. Open the side menu by clicking the the Grafana icon in the top header.
|
||||
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
|
||||
|
||||
> NOTE: If this link is missing in the side menu it means that your current user does not have the `Admin` role for the current organization.
|
||||
|
||||
@@ -51,6 +51,13 @@ When using OpenTSDB with a template variable of `query` type you can use followi
|
||||
|
||||
If you do not see template variables being populated in `Preview of values` section, you need to enable `tsd.core.meta.enable_realtime_ts` in the OpenTSDB server settings. Also, to populate metadata of the existing time series data in OpenTSDB, you need to run `tsdb uid metasync` on the OpenTSDB server.
|
||||
|
||||
### Nested Templating
|
||||
|
||||
One template variable can be used to filter tag values for another template varible. Very importantly, the order of the parameters matter in tag_values function. First parameter is the metric name, second parameter is the tag key for which you need to find tag values, and after that all other dependent template variables. Some examples are mentioned below to make nested template queries work successfully.
|
||||
|
||||
tag_values(cpu, hostname, env=$env) // return tag values for cpu metric, selected env tag value and tag key hostname
|
||||
tag_values(cpu, hostanme, env=$env, region=$region) // return tag values for cpu metric, selected env tag value, selected region tag value and tag key hostname
|
||||
|
||||
> Note: This is required for the OpenTSDB `lookup` api to work.
|
||||
|
||||
For details on opentsdb metric queries checkout the official [OpenTSDB documentation](http://opentsdb.net/docs/build/html/index.html)
|
||||
|
||||
68
docs/sources/guides/whats-new-in-v3-1.md
Normal file
68
docs/sources/guides/whats-new-in-v3-1.md
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
page_title: What's New in Grafana v3.1
|
||||
page_description: What's new in Grafana v3.1
|
||||
page_keywords: grafana, new, changes, features, documentation
|
||||
---
|
||||
|
||||
# What's New in Grafana v3.1
|
||||
|
||||
## Dashboard Export & Import
|
||||
|
||||
The export feature is now accessed from the share menu.
|
||||
|
||||
<img src="/img/v31/export_menu.png">
|
||||
|
||||
Dashboards exported from Grafana 3.1 are now more portable and easier for others to import than before.
|
||||
The export process extracts information data source types used by panels and adds these to a new `inputs`
|
||||
section in the dashboard json. So when you or another person tries to import the dashboard they will be asked to
|
||||
select data source and optional metrix prefix options.
|
||||
|
||||
<img src="/img/v31/import_step1.png">
|
||||
|
||||
The above screenshot shows the new import modal that gives you 3 options for how to import a dashboard.
|
||||
One notable new addition here is the ability to import directly from Dashboards shared on [Grafana.net](https://grafana.net).
|
||||
|
||||
The next step in the import process:
|
||||
|
||||
<img src="/img/v31/import_step2.png">
|
||||
|
||||
Here you can change the name of the dashboard and also pick what data sources you want the dashboard to use. The above screenshot
|
||||
shows a CollectD dashboard for Graphite that requires a metric prefix be specified.
|
||||
|
||||
## Discover Dashboards
|
||||
|
||||
On [Grafana.net](https://grafana.net) you can now browse & search for dashboards. We have already added a few but
|
||||
more are being uploaded every day. To import a dashboard just copy the dashboard url and head back to Grafana,
|
||||
then Dashboard Search -> Import -> Paste Grafana.net Dashboard URL.
|
||||
|
||||
<img src="/img/v31/gnet_dashboards_list.png">
|
||||
|
||||
## Constant template variables
|
||||
|
||||
We added a new template variable named constant that makes it easier to share and export dashboard that have custom prefixes.
|
||||
|
||||
## Dashboard Urls
|
||||
Having current time range and template variable value always sync with the URL makes it possible to always copy your current
|
||||
Grafana url to share with a colleague without having to use the Share modal.
|
||||
|
||||
## Internal metrics
|
||||
|
||||
Do you want metrics about viewing metrics? Ofc you do! In this release we added support for sending metrics about Grafana to graphite.
|
||||
You can configure interval and server in the config file.
|
||||
|
||||
## Logging
|
||||
|
||||
Switched logging framework to log15 to enable key value per logging and filtering based on different log levels.
|
||||
Its now possible to configure different log levels for different modules.
|
||||
|
||||
### Breaking changes
|
||||
- **Logging** format have been changed to improve log filtering.
|
||||
- **Graphite PNG** Graphite PNG support dropped from Graph panel (use Grafana native PNG instead).
|
||||
- **Migration** No longer possible to migrate dashboards from 1.x (Stored in ES or Influx 0.8).
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
For a detailed list and link to github issues for everything included
|
||||
in the 3.1 release please view the
|
||||
[CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md)
|
||||
file.
|
||||
223
docs/sources/guides/whats-new-in-v3.md
Normal file
223
docs/sources/guides/whats-new-in-v3.md
Normal file
@@ -0,0 +1,223 @@
|
||||
---
|
||||
page_title: What's New in Grafana v3.0
|
||||
page_description: What's new in Grafana v3.0
|
||||
page_keywords: grafana, new, changes, features, documentation
|
||||
---
|
||||
|
||||
# What's New in Grafana v3.0
|
||||
|
||||
## Commercial Support
|
||||
|
||||
Commercial Support subscriptions for Grafana are now [generally available](https://grafana.net/support/plans/).
|
||||
|
||||
Raintank is committed to a 100% open-source strategy for Grafana. We
|
||||
do not want to go down the “open core” route. If your organization
|
||||
finds Grafana valuable, please consider purchasing a subscription. Get
|
||||
direct support, bug fixes, and training from the core Grafana team.
|
||||
|
||||
## Plugins
|
||||
|
||||
With the popularity of Grafana continuing to accelerate, it has been
|
||||
challenging to keep up with all the requests for new features, new
|
||||
panels, new data sources, and new functionality. Saying “no” so often
|
||||
has been frustrating, especially for an open source project with such
|
||||
a vibrant community.
|
||||
|
||||
The team felt that it was time to dramatically improve extensibility
|
||||
through plugin support. Grafana 3.0 comes with a completely revamped
|
||||
plugin SDK / API.
|
||||
|
||||
We’ve refactored our **Data Source** plugin architecture and added
|
||||
two new plugin types:
|
||||
|
||||
* **Panel** plugins let you add new panel types for your Dashboards.
|
||||
* **App** plugins bundle **Panels** plugins, **Data Sources** plugins,
|
||||
Dashboards, and Grafana **Pages**. Apps are a great way to provide an
|
||||
entire experience right within Grafana.
|
||||
|
||||
## Grafana.net
|
||||
|
||||
<img src="/img/v3/grafana_net_tour.png">
|
||||
|
||||
[Grafana.net](https://grafana.net) offers a central repository where the community can come together to discover, create and
|
||||
share plugins (data sources, panels, apps) and dashboards.
|
||||
|
||||
We are also working on a hosted Graphite-compatible data source that will be optimized for use with Grafana.
|
||||
It’ll be easy to combine your existing data source(s) with this OpenSaaS option. Finally, Grafana.net can
|
||||
also be a hub to manage all your Grafana instances. You’ll be able to monitor their health and availability,
|
||||
perform dashboard backups, and more.
|
||||
|
||||
We are also working on a hosted Graphite-compatible Data Source that
|
||||
will be optimized for use with Grafana. It’ll be easy to combine your
|
||||
existing Data Source(s) with this OpenSaaS option.
|
||||
|
||||
Finally, Grafana.net will also be a hub to manage all your Grafana
|
||||
instances. You’ll be able to monitor their health and availability,
|
||||
perform Dashboard backups, and more.
|
||||
|
||||
Grafana.net will officially launch along with the stable version of
|
||||
Grafana 3.0, but <a href=http://www.grafana.net>check out the preview
|
||||
and sign up for an account</a> in the meantime.
|
||||
|
||||
|
||||
## grafana-cli
|
||||
|
||||
Grafana 3.0 comes with a new command line tool called grafana-cli. You
|
||||
can easily install plugins from Grafana.net with it. For
|
||||
example:
|
||||
|
||||
```
|
||||
grafana-cli install grafana-pie-chart-panel
|
||||
```
|
||||
|
||||
## Personalization & Preferences
|
||||
|
||||
The home dashboard, timezone and theme can now be customized on Organization
|
||||
and user Profile level. Grafana can also track recently viewed dashboards, which
|
||||
can then be displayed in the dashboard list panel.
|
||||
|
||||
## Improved Playlists
|
||||
|
||||
You can now save Playlists, and start them by using a Playlist URL. If
|
||||
you update a running Playlist, it will update after its next cycle.
|
||||
|
||||
This is powerful as it allows you to remote control Grafana. If you
|
||||
have a big TV display showing Grafana in your company lobby, create a
|
||||
playlist named Lobby, and start it on the computer connected to the
|
||||
Lobby TV.
|
||||
|
||||
You can now change the Lobby playlist and have the dashboards shown in
|
||||
the Lobby update accordingly, automatically.
|
||||
|
||||
The playlist does not even have to contain multiple Dashboards; you
|
||||
can use this feature to reload the whole Dashboard (and Grafana)
|
||||
periodically and remotely.
|
||||
|
||||
You can also make Playlists dynamic by using Dashboard **tags** to
|
||||
define the Playlist.
|
||||
|
||||
<img src="/img/v3/playlist.png">
|
||||
|
||||
## Improved UI
|
||||
|
||||
We’ve always tried to focus on a good looking, usable, and responsive
|
||||
UI. We’ve continued to pay a lot of attention to these areas in this
|
||||
release.
|
||||
|
||||
Grafana 3.0 has a dramatically updated UI that not only looks better
|
||||
but also has a number of usability improvements. The side menu now
|
||||
works as a dropdown that you can pin to the side. The Organization /
|
||||
Profile / Sign out side menu links have been combined into an on hover
|
||||
slide out menu.
|
||||
|
||||
In addition, all the forms and the layouts of all pages have been
|
||||
updated to look and flow better, and be much more consistent. There
|
||||
are literally hundreds of UI improvements and refinements.
|
||||
|
||||
Here’s the new side menu in action:
|
||||
|
||||
<img src="/img/v3/menu.gif">
|
||||
|
||||
And here's the new look for Dashboard settings:
|
||||
|
||||
<img src="/img/v3/dashboard_settings.png">
|
||||
|
||||
Check out the <a href="http://play.grafana.org" target="_blank">Play
|
||||
Site</a> to get a feel for some of the UI changes.
|
||||
|
||||
## Improved Annotations
|
||||
|
||||
It is now possible to define a link in each annotation. You can hover
|
||||
over the link and click the annotation text. This feature is very
|
||||
useful for linking to particular commits or tickets where more
|
||||
detailed information can be presented to the user.
|
||||
|
||||
<img src="/img/v3/annotation_links.gif">
|
||||
|
||||
## Data source variables
|
||||
|
||||
This has been a top requested feature for very long we are exited to finally provide
|
||||
this feature. You can now add a new `Data source` type variable. That will
|
||||
automatically be filled with instance names of your data sources.
|
||||
|
||||
<img src="/img/v3/data_source_variable.png">
|
||||
|
||||
You can then use this variable as the panel data source:
|
||||
|
||||
<img src="/img/v3/data_source_variable_use.png">
|
||||
|
||||
This will allow you to quickly change data source server and reuse the
|
||||
same dashboard for different instances of your metrics backend. For example
|
||||
you might have Graphite running in multiple data centers or environments.
|
||||
|
||||
## Prometheus, InfluxDB, and OpenTSDB improvements
|
||||
|
||||
All three of these popular included Data Sources have seen a variety
|
||||
of improvements in this release. Here are some highlights:
|
||||
|
||||
### Prometheus
|
||||
|
||||
The Prometheus Data Source now supports annotations.
|
||||
|
||||
### InfluxDB
|
||||
|
||||
You can now select the InfluxDB policy from the query editor.
|
||||
<img src="/img/v3/influxdb_policy.png">
|
||||
|
||||
Grafana 3.0 also comes with support for InfluxDB 0.11 and InfluxDB 0.12.
|
||||
|
||||
### OpenTSDB
|
||||
|
||||
OpenTSDB 2.2 is better supported and now supports millisecond precision.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
Dashboards from v2.6 are compatible; no manual updates should be necessary. There could
|
||||
be some edge case scenarios where dashboards using templating could stop working.
|
||||
If that is the case just enter the edit view for the template variable and hit Update button.
|
||||
This is due to a simplification of the variable format system where template variables are
|
||||
now stored without any formatting (glob/regex/etc), this is done on the fly when the
|
||||
variable is interpolated.
|
||||
|
||||
* Plugin API: The plugin API has changed so if you are using a custom
|
||||
data source (or panel) they need to be updated as well.
|
||||
|
||||
* InfluxDB 0.8: This data source is no longer included in releases,
|
||||
you can still install manually from [Grafana.net](http://grafana.net)
|
||||
|
||||
* KairosDB: This data source has also no longer shipped with Grafana,
|
||||
you can install it manually from [Grafana.net](http://grafana.net)
|
||||
|
||||
## Plugin showcase
|
||||
|
||||
Discovering and installing plugins is very quick and easy with Grafana 3.0 and [Grafana.net](https://grafana.net). Here
|
||||
are a couple that I incurage you try!
|
||||
|
||||
#### [Clock Panel](https://grafana.net/plugins/grafana-clock-panel)
|
||||
Support's both current time and count down mode.
|
||||
<img src="/img/v3/clock_panel.png">
|
||||
|
||||
#### [Pie Chart Panel](https://grafana.net/plugins/grafana-piechart-panel)
|
||||
A simple pie chart panel is now available as an external plugin.
|
||||
<img src="/img/v3/pie_chart_panel.png">
|
||||
|
||||
#### [WorldPing App](https://grafana.net/plugins/raintank-worldping-app)
|
||||
This is full blown Grafana App that adds new panels, data sources and pages to give
|
||||
feature rich global performance monitoring directly from your on-prem Grafana.
|
||||
|
||||
<img src="/img/v3/wP-Screenshot-dash-web.png">
|
||||
|
||||
#### [Zabbix App](https://grafana.net/plugins/alexanderzobnin-zabbix-app)
|
||||
This app contains the already very pouplar Zabbix data source plugin, 2 dashboards and a triggers panel. It is
|
||||
created and maintained by [Alexander Zobnin](https://github.com/alexanderzobnin/grafana-zabbix).
|
||||
|
||||
<img src="/img/v3/zabbix_app.png">
|
||||
|
||||
Checkout the full list of plugins on [Grafana.net](https://grafana.net/plugins)
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
For a detailed list and link to github issues for everything included
|
||||
in the 3.0 release please view the
|
||||
[CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md)
|
||||
file.
|
||||
@@ -191,7 +191,7 @@ Will return the home dashboard.
|
||||
|
||||
`GET /api/dashboards/tags`
|
||||
|
||||
Get all tabs of dashboards
|
||||
Get all tags of dashboards
|
||||
|
||||
**Example Request**:
|
||||
|
||||
|
||||
@@ -207,35 +207,6 @@ page_keywords: grafana, admin, http, api, documentation, datasource
|
||||
|
||||
{"message":"Data source deleted"}
|
||||
|
||||
## Available data source types
|
||||
|
||||
`GET /api/datasources/plugins`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
GET /api/datasources/plugins HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
**Example Response**:
|
||||
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"grafana":{
|
||||
"metrics":true,"module":"plugins/datasource/grafana/datasource",
|
||||
"name":"Grafana (for testing)",
|
||||
"partials":{
|
||||
"query":"app/plugins/datasource/grafana/partials/query.editor.html"
|
||||
},
|
||||
"pluginType":"datasource",
|
||||
"serviceName":"GrafanaDatasource",
|
||||
"type":"grafana"
|
||||
}
|
||||
}
|
||||
|
||||
## Data source proxy calls
|
||||
|
||||
`GET /api/datasources/proxy/:datasourceId/*`
|
||||
|
||||
@@ -18,4 +18,5 @@ dashboards, creating users and updating data sources.
|
||||
* [User API](/http_api/user/)
|
||||
* [Admin API](/http_api/admin/)
|
||||
* [Snapshot API](/http_api/snapshot/)
|
||||
* [Preferences API](/http_api/preferences/)
|
||||
* [Other API](/http_api/other/)
|
||||
|
||||
100
docs/sources/http_api/preferences.md
Normal file
100
docs/sources/http_api/preferences.md
Normal file
@@ -0,0 +1,100 @@
|
||||
----
|
||||
page_title: Preferences API
|
||||
page_description: Grafana Preferences API Reference
|
||||
page_keywords: grafana, preferences, http, api, documentation
|
||||
---
|
||||
|
||||
# User and Org Preferences API
|
||||
|
||||
Keys:
|
||||
|
||||
- **theme** - One of: ``light``, ``dark``, or an empty string for the default theme
|
||||
- **homeDashboardId** - The numerical ``:id`` of a favorited dashboard, default: ``0``
|
||||
- **timezone** - One of: ``utc``, ``browser``, or an empty string for the default
|
||||
|
||||
Omitting a key will cause the current value to be replaced with the
|
||||
system default value.
|
||||
|
||||
## Get Current User Prefs
|
||||
|
||||
`GET /api/user/preferences`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
GET /api/user/preferences HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
**Example Response**:
|
||||
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
{"theme":"","homeDashboardId":0,"timezone":""}
|
||||
|
||||
## Update Current User Prefs
|
||||
|
||||
`PUT /api/user/preferences`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
PUT /api/user/preferences HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
{
|
||||
"theme": "",
|
||||
"homeDashboardId":0,
|
||||
"timezone":"utc"
|
||||
}
|
||||
|
||||
**Example Response**:
|
||||
|
||||
HTTP/1.1 200
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
{"message":"Preferences updated"}
|
||||
|
||||
## Get Current Org Prefs
|
||||
|
||||
`GET /api/org/preferences`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
GET /api/org/preferences HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
**Example Response**:
|
||||
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
{"theme":"","homeDashboardId":0,"timezone":""}
|
||||
|
||||
## Update Current Org Prefs
|
||||
|
||||
`PUT /api/org/preferences`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
PUT /api/org/preferences HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
{
|
||||
"theme": "",
|
||||
"homeDashboardId":0,
|
||||
"timezone":"utc"
|
||||
}
|
||||
|
||||
**Example Response**:
|
||||
|
||||
HTTP/1.1 200
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
{"message":"Preferences updated"}
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
page_title: Grafana Installation
|
||||
page_description: Install guide for Grafana.
|
||||
page_description: Install guide for Grafana
|
||||
page_keywords: grafana, installation, documentation
|
||||
---
|
||||
|
||||
|
||||
@@ -44,6 +44,12 @@ Then you can override them using:
|
||||
|
||||
<hr />
|
||||
|
||||
## instance_name
|
||||
Set the name of the grafana-server instance. Used in logging and internal metrics and in
|
||||
clustering info. Defaults to: `${HOSTNAME}`, which will be replaced with
|
||||
environment variable `HOSTNAME`, if that is empty or does not exist Grafana will try to use
|
||||
system calls to get the machine name.
|
||||
|
||||
## [paths]
|
||||
|
||||
### data
|
||||
@@ -186,7 +192,7 @@ Defaults to `admin`.
|
||||
|
||||
### admin_password
|
||||
|
||||
The password of the default Grafana admin. Defaults to `admin`.
|
||||
The password of the default Grafana admin. Set once on first-run. Defaults to `admin`.
|
||||
|
||||
### login_remember_days
|
||||
|
||||
@@ -226,7 +232,7 @@ organization to be created for that new user.
|
||||
|
||||
The role new users will be assigned for the main organization (if the
|
||||
above setting is set to true). Defaults to `Viewer`, other valid
|
||||
options are `Admin` and `Editor`.
|
||||
options are `Admin` and `Editor` and `Read-Only Editor`.
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -439,3 +445,35 @@ Grafana backend index those json dashboards which will make them appear in regul
|
||||
|
||||
### path
|
||||
The full path to a directory containing your json dashboards.
|
||||
|
||||
## [log]
|
||||
|
||||
### mode
|
||||
Either "console", "file", "syslog". Default is console and file
|
||||
Use space to separate multiple modes, e.g. "console file"
|
||||
|
||||
### level
|
||||
Either "debug", "info", "warn", "error", "critical", default is "info"
|
||||
|
||||
### filter
|
||||
optional settings to set different levels for specific loggers.
|
||||
Ex `filters = sqlstore:debug`
|
||||
|
||||
## [metrics]
|
||||
|
||||
### enabled
|
||||
Enable metrics reporting. defaults true. Available via HTTP API `/api/metrics`.
|
||||
|
||||
### interval_seconds
|
||||
|
||||
Flush/Write interval when sending metrics to external TSDB. Defaults to 60s.
|
||||
|
||||
## [metrics.graphite]
|
||||
Include this section if you want to send internal Grafana metrics to Graphite.
|
||||
|
||||
### address
|
||||
Format `<Hostname or ip>`:port
|
||||
|
||||
### prefix
|
||||
Graphite metric prefix. Defaults to `prod.grafana.%(instance_name)s.`
|
||||
|
||||
|
||||
@@ -10,20 +10,13 @@ page_keywords: grafana, installation, debian, ubuntu, guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable .deb for Debian-based Linux | [grafana_2.6.0_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb)
|
||||
Beta .deb for Debian-based Linux | [grafana_3.0.0-beta31460467884_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta31460467884_amd64.deb)
|
||||
Stable .deb for Debian-based Linux | [3.1.1 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb)
|
||||
|
||||
## Install Stable
|
||||
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb
|
||||
$ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_2.6.0_amd64.deb
|
||||
|
||||
## Install 3.0 Beta
|
||||
|
||||
$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta31460467884_amd64.deb
|
||||
$ sudo apt-get install -y adduser libfontconfig
|
||||
$ sudo dpkg -i grafana_3.0.0-beta31460467884_amd64.deb
|
||||
$ sudo dpkg -i grafana_3.1.1-1470047149_amd64.deb
|
||||
|
||||
## APT Repository
|
||||
|
||||
|
||||
@@ -6,8 +6,33 @@ page_keywords: grafana, installation, mac, osx, guide
|
||||
|
||||
# Installing on Mac
|
||||
|
||||
There is currently no binary build for Mac, but Grafana will happily build on Mac. Read the [build from
|
||||
source](/project/building_from_source) page for instructions on how to
|
||||
build it yourself.
|
||||
Installation can be done using [homebrew](http://brew.sh/)
|
||||
|
||||
Install latest stable:
|
||||
|
||||
```
|
||||
brew install grafana/grafana/grafana
|
||||
```
|
||||
|
||||
To start grafana look at the command printed after the homebrew install completes.
|
||||
|
||||
You can also add the grafana as tap.
|
||||
|
||||
```
|
||||
brew tap grafana/grafana
|
||||
brew install grafana
|
||||
```
|
||||
|
||||
Install latest unstable from master:
|
||||
|
||||
```
|
||||
brew install --HEAD grafana/grafana/grafana
|
||||
```
|
||||
|
||||
To upgrade use the reinstall command
|
||||
|
||||
```
|
||||
brew reinstall --HEAD grafana/grafana/grafana
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -10,43 +10,24 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.6.0-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm)
|
||||
Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta31460467884.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta31460467884§.x86_64.rpm)
|
||||
Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [3.1.1 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-3.1.1-1470047149.x86_64.rpm)
|
||||
|
||||
## Install Stable Release from package file
|
||||
## Install Latest Stable
|
||||
|
||||
You can install Grafana using Yum directly.
|
||||
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.1.1-1470047149.x86_64.rpm
|
||||
|
||||
Or install manually using `rpm`.
|
||||
|
||||
#### On CentOS / Fedora / Redhat:
|
||||
|
||||
$ sudo yum install initscripts fontconfig
|
||||
$ sudo rpm -Uvh grafana-2.6.0-1.x86_64.rpm
|
||||
$ sudo rpm -Uvh grafana-3.1.1-1470047149.x86_64.rpm
|
||||
|
||||
#### On OpenSuse:
|
||||
|
||||
$ sudo rpm -i --nodeps grafana-2.6.0-1.x86_64.rpm
|
||||
|
||||
## Install Beta Release from package file
|
||||
|
||||
You can install Grafana using Yum directly.
|
||||
|
||||
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta31460467884.x86_64.rpm
|
||||
|
||||
Or install manually using `rpm`.
|
||||
|
||||
#### On CentOS / Fedora / Redhat:
|
||||
|
||||
$ sudo yum install initscripts fontconfig
|
||||
$ sudo rpm -Uvh grafana-3.0.0-beta31460467884.x86_64.rpm
|
||||
|
||||
#### On OpenSuse:
|
||||
|
||||
$ sudo rpm -i --nodeps grafana-3.0.0-beta31460467884.x86_64.rpm
|
||||
|
||||
$ sudo rpm -i --nodeps grafana-3.1.1-1470047149.x86_64.rpm
|
||||
|
||||
## Install via YUM Repository
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ page_keywords: grafana, installation, windows guide
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable Zip package for Windows | [grafana.2.6.0.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.5.0.windows-x64.zip)
|
||||
Stable Zip package for Windows | [grafana.3.1.1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.1.1.windows-x64.zip)
|
||||
|
||||
## Configure
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Grafana already have a strong community of contributors and plugin developers.
|
||||
By making it easier to develop and install plugins we hope that the community
|
||||
can grow even stronger and develop new plugins that we would never think about.
|
||||
|
||||
You can discover available plugins on [Grafana.net](http://grafana.net)
|
||||
You can discover available plugins on [Grafana.net](https://grafana.net)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,3 +40,10 @@ as the name for the fields that should be used for the annotation title, tags an
|
||||
For InfluxDB you need to enter a query like in the above screenshot. You need to have the ```where $timeFilter``` part.
|
||||
If you only select one column you will not need to enter anything in the column mapping fields.
|
||||
|
||||
## Prometheus Annotations
|
||||

|
||||
|
||||
Prometheus supports two ways to query annotations.
|
||||
|
||||
- A regular metric query
|
||||
- A Prometheus query for pending and firing alerts (for details see [Inspecting alerts during runtime](https://prometheus.io/docs/alerting/rules/#inspecting-alerts-during-runtime))
|
||||
|
||||
@@ -26,7 +26,6 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized
|
||||
{
|
||||
"id": null,
|
||||
"title": "New dashboard",
|
||||
"originalTitle": "New dashboard",
|
||||
"tags": [],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
@@ -59,7 +58,6 @@ Each field in the dashboard JSON is explained below with its usage:
|
||||
| ---- | ----- |
|
||||
| **id** | unique dashboard id, an integer |
|
||||
| **title** | current title of dashboard |
|
||||
| **originalTitle** | title of dashboard when saved for the first time |
|
||||
| **tags** | tags associated with dashboard, an array of strings |
|
||||
| **style** | theme of dashboard, i.e. `dark` or `light` |
|
||||
| **timezone** | timezone of dashboard, i.e. `utc` or `browser` |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user