Compare commits

...

656 Commits

Author SHA1 Message Date
Torkel Ödegaard
2bfccd77d4 docs(): updated release links 2016-08-01 12:47:55 +02:00
Torkel Ödegaard
a4d27083d0 fix(tests): fixed unit test broken in recent dynamic dashboard fix 2016-08-01 12:20:16 +02:00
Torkel Ödegaard
a9cf7cd4f0 fix(light theme): fixes issue with hidden queries in light theme, fixes #5697 2016-08-01 11:58:12 +02:00
Torkel Ödegaard
44d1393480 fix(templating): fixed issue with panel/row repeat when saving dashboard, fixes #5591 2016-08-01 10:50:33 +02:00
Torkel Ödegaard
b46af0069e fix(footer): fixed link in footer, #5690 2016-08-01 10:09:43 +02:00
Torkel Ödegaard
741b7353c1 Merge branch 'v3.1.x' of github.com:grafana/grafana into v3.1.x 2016-07-29 15:06:09 +02:00
Torkel Ödegaard
c4e7a3ae89 fix(png rendering): another fix for #5606 2016-07-29 15:04:51 +02:00
Torkel Ödegaard
89dc3b88d1 fix(test): fixed failing test caused by recent change 2016-07-27 10:20:48 +02:00
Torkel Ödegaard
971e2d62f1 fix(zoom): fixed zoom in and out issues when graph is embedded, fixes #5666, fixes #4489 2016-07-27 09:36:35 +02:00
Torkel Ödegaard
66a72e9ece changed version to 3.1.1 2016-07-25 12:20:21 +02:00
Torkel Ödegaard
0de0f4d014 feat(templating): fixed issue with template variables set to reload on dashboard load being issued multiple times, fixes #5637 2016-07-25 12:02:59 +02:00
Torkel Ödegaard
9f777a535b fix(): removed dashboard version to schema version migration 2016-07-23 13:29:48 +02:00
Torkel Ödegaard
ddf579f204 fix(mixed data sources): fix when using two graphite data sources in mixed mode, fixes #5617 2016-07-23 12:54:11 +02:00
Torkel Ödegaard
3abbf08a17 tech(): upgrade jquery to 2.2.4, closes #5627 2016-07-23 12:00:45 +02:00
Torkel Ödegaard
474a821767 fix(elasticsearch): fix json escape logic when doing terms template value lookup, fixes #5485 2016-07-23 11:52:49 +02:00
Torkel Ödegaard
3ae327320a fix(prometheus): fixed svg link in prometheus dashboard, fixes #5604 2016-07-18 16:27:02 +02:00
Torkel Ödegaard
78d0badffe Merge branch 'v3.1.x' of github.com:grafana/grafana into v3.1.x 2016-07-18 16:22:31 +02:00
Torkel Ödegaard
575b015fe0 fix(panel rendering): Fixed png panel rendering timing issue, #5606 2016-07-18 16:18:00 +02:00
Torkel Ödegaard
b9a2546a10 fix(iframe): fixed issue with using full height of iframe, fixes #5605 2016-07-18 16:17:46 +02:00
Torkel Ödegaard
6c2a61001a docs(): updated download links 2016-07-12 13:19:20 +02:00
Torkel Ödegaard
d007363e7c bumbped version from beta1 to stable 2016-07-12 08:42:28 +02:00
Torkel Ödegaard
b2acac3a41 feat(apps): more polish on app dashboard save warning, #5529 2016-07-12 08:41:56 +02:00
Torkel Ödegaard
f3db2fa262 feat(plugins): hide link on small screens 2016-07-11 19:16:35 +02:00
Torkel Ödegaard
5b4fd8e9c8 Merge branch 'v3.1.x' of github.com:grafana/grafana into v3.1.x 2016-07-11 19:07:32 +02:00
Torkel Ödegaard
81af8f072c feat(links): updated links to grafana.net 2016-07-11 19:07:16 +02:00
stuart nelson
eb35f8cb89 [prometheus] Use panelId and target.refId for requestId
Using these two values ties requests to a
particular query position within a panel, ensuring
that requests are canceled if:

- Duplicate requests with the same query are sent
- Requests from the same query position (but a
different query) are sent

The last point is important as it identifies
queries by a physical location in the dashboard
instead of with the query expression.  If a
different query from the same position in a panel
is sent, the previous request should be canceled.
2016-07-11 14:47:14 +02:00
Torkel Ödegaard
65683ab241 feat(table): added sanitize html option to column styles for table panel, fixes #4596 2016-07-11 09:38:06 +02:00
Torkel Ödegaard
4c4cb20bde tech(sass): changed sass lint version to 1.7.0 2016-07-08 22:12:10 +02:00
Torkel Ödegaard
4133526d8d feat(build): updated sass lint 2016-07-08 21:04:58 +02:00
Torkel Ödegaard
12d455f3c3 Merge branch 'v3.1.x' of github.com:grafana/grafana into v3.1.x 2016-07-08 18:23:15 +02:00
Torkel Ödegaard
615b692442 feat(apps): fixed unit tests 2016-07-08 18:21:25 +02:00
Torkel Ödegaard
ebdf0564eb feat(apps): plugin dashboard sync is starting to work 2016-07-08 17:44:57 +02:00
Torkel Ödegaard
68a8d9bc91 feat(apps): more work on plugin dashboard sync 2016-07-08 13:41:46 +02:00
Torkel Ödegaard
85be7dd902 feat(apps): progress on app dashboard sync 2016-07-08 12:26:51 +02:00
Torkel Ödegaard
d44325affd feat(apps): progress on app dashboard imports 2016-07-08 09:35:06 +02:00
Fraser Savage
5a8efa9a52 Update configuration.md (#5527)
Insert missing backtick.
2016-07-08 07:12:26 +02:00
Torkel Ödegaard
b62f1f00cd feat(apps): auto update dashboard dashboards, #5529 2016-07-07 18:11:03 +02:00
Torkel Ödegaard
4545b4d323 fix(login): minor fix redirect on login change 2016-07-07 14:48:22 +02:00
Torkel Ödegaard
d74eb8c188 fix(login): fixed so that you get redirect back to the page or dashboard you where on when you clicked on sign in link, fixes #3312 2016-07-06 10:09:53 +02:00
Torkel Ödegaard
b275fa8109 fix(alerts): fixed login and other alert popups not showing, fixes #5435 2016-06-25 17:42:08 +02:00
Torkel Ödegaard
60f45c965c Merge branch 'master' of github.com:grafana/grafana 2016-06-24 10:25:44 +02:00
Torkel Ödegaard
efad4bcb56 docs(): updated changelog 2016-06-23 17:45:29 +02:00
Torkel Ödegaard
9435e70b37 docs(): spelling fix 2016-06-23 17:31:22 +02:00
bergquist
2063fee4fe docs(changelog): add note about cli fix #5410 2016-06-23 15:16:26 +02:00
Torkel Ödegaard
c3e1955792 docs(): updated export docs 2016-06-23 13:21:30 +02:00
Torkel Ödegaard
838284c09f docs(): updated changelog 2016-06-23 10:38:11 +02:00
Torkel Ödegaard
1d35b90484 docs(): updated download links 2016-06-23 10:35:47 +02:00
Torkel Ödegaard
f3c1a894de changed version to 3.1-beta1 2016-06-23 09:12:17 +02:00
bergquist
af1c8dc5d9 feat(cli): adds support for dist/plugin.json location for plugins
ref #5410
2016-06-23 08:35:40 +02:00
bergquist
2123fbdf9b feat(cli): make remove command an alias for uninstall 2016-06-23 08:21:55 +02:00
bergquist
14169c5092 tech(docker): add memcached exporter target for prom 2016-06-22 17:36:22 +02:00
Torkel Ödegaard
0555525f97 tech(): updated list of docker stuff 2016-06-22 11:01:11 +02:00
Torkel Ödegaard
24a54cd95b feat(units): refactoring #5404 2016-06-21 21:08:07 +02:00
Torkel Ödegaard
a7a5f36b49 Merge branch 'issue-2971' of https://github.com/alexanderzobnin/grafana into alexanderzobnin-issue-2971 2016-06-21 21:00:00 +02:00
Alexander Zobnin
ab0155c861 Issue #2971 - add time units for use in singlestat panel. 2016-06-21 20:56:34 +03:00
Torkel Ödegaard
53c424caf8 docs(): title change 2016-06-21 18:25:24 +02:00
Torkel Ödegaard
23cfbac4ec feat(docs): updated import / export docs 2016-06-21 18:24:25 +02:00
Torkel Ödegaard
f23d72001d fix(dashboard): fixed issue triggering refresh after leaving fullscreen/edit mode with time range change 2016-06-21 17:21:45 +02:00
Torkel Ödegaard
302ad5f1f9 Merge branch 'master' of github.com:grafana/grafana 2016-06-21 17:08:16 +02:00
Torkel Ödegaard
257e6c469e feat(collectd): updated collectd config 2016-06-21 17:07:01 +02:00
bergquist
ef9766eb96 docs(3.1): initial post about whats new in 3.1 2016-06-21 16:29:17 +02:00
bergquist
aa9e524e73 tech(docker): add node exporter to prometheus 2016-06-21 11:46:08 +02:00
Carl Bergquist
3b1ae3f7d2 Merge pull request #5396 from hailthemelody/fix_issue_template_typos
fix typos in GitHub Issue Template
2016-06-21 10:27:41 +02:00
hailthemelody
cccfe47bf0 fix typos in GitHub Issue Template 2016-06-20 21:39:11 -04:00
Carl Bergquist
87ab97b5ed Merge pull request #5391 from wkruse/prometheus-annotations-doc
Add Prometheus annotations doc
2016-06-20 18:49:00 +02:00
Wadim Kruse
3b47b1ecbd Add Prometheus annotations doc 2016-06-20 18:36:05 +02:00
bergquist
12706fd6db Revert "docs(changelog): add note about singlestat to datetime func"
This reverts commit 8efa94e42a.
2016-06-20 11:04:01 +02:00
Carl Bergquist
d8be2f1ecc Merge pull request #5389 from grafana/revert-5383-issue-4747
Revert "issue #4747 - add date and time units to singlestat panel."
2016-06-20 11:02:43 +02:00
Carl Bergquist
b6f9d9feb0 Revert "issue #4747 - add date and time units to singlestat panel." 2016-06-20 11:02:29 +02:00
bergquist
8efa94e42a docs(changelog): add note about singlestat to datetime func 2016-06-20 10:59:47 +02:00
Carl Bergquist
b94527f661 Merge pull request #5383 from alexanderzobnin/issue-4747
issue #4747 - add date and time units to singlestat panel.
2016-06-20 10:57:08 +02:00
bergquist
3adee1eda0 tech(sass): sasslint fixes for css3
Pseudo-elements must start with double colons pseudo-element
2016-06-20 10:37:47 +02:00
Alexander Zobnin
398e9f5195 issue #4747 - add date and time units to singlestat panel. 2016-06-17 22:51:08 +03:00
Torkel Ödegaard
90c063060a fix(png): fixed phantomjs rendering issue with graph and y-axis label rotation, fixes #5220 2016-06-17 14:36:10 +02:00
Torkel Ödegaard
3bcda9268a feat(styleguide): removed unused/empty tabs 2016-06-17 14:18:24 +02:00
Torkel Ödegaard
e2b398a6bf Merge branch 'master' of github.com:grafana/grafana 2016-06-17 14:16:25 +02:00
Torkel Ödegaard
fa10fc994a fix(graph): remove panel width cache, causing issues, does not handle window resize and fullscreen to dashboard, #5297 2016-06-17 14:16:01 +02:00
Drew Farris
cb2b8dea96 OpenTSDB: consistent options for http requests (#5233)
* OpenTSDB: consistent options for http requests

 . the get function wasn't using the same request options wrt to credentials/auth as
   the timeseries http request

* OpenTSDB: `_get` `_performTimeSeriesQuery` refactor copied code
2016-06-17 14:04:40 +02:00
Torkel Ödegaard
9bcd5de8ff fix(share): fixed PNG render link generated from share modal when opened from edit mode, fixes #5295 2016-06-17 14:03:59 +02:00
Torkel Ödegaard
9f9fca1e76 feat(datasource): added suggest urls for each data source, #4577 2016-06-17 13:35:29 +02:00
Alexander Zobnin
fdf46c6a10 Issue 4577 (#5379)
* Add default-url property for datasource-http-settings directive.
This will allow to set default url for datasource.

* Fixed spelling.

* Use typeahead for url suggestion.
2016-06-17 13:18:00 +02:00
Torkel Ödegaard
305a6ae110 feat(dashboards): dashboard sharing fixes 2016-06-17 11:36:35 +02:00
Torkel Ödegaard
10daf1d63a Revert "Enable the "limit" param in /api/search"
This reverts commit 3d77685108.
2016-06-17 11:22:39 +02:00
Torkel Ödegaard
23aa614baf feat(rendering): fixed issue with png rendering, recently introduced by profiler refactoring 2016-06-17 08:49:11 +02:00
Torkel Ödegaard
5c35fac8fe fix(dataproxy): removed accidental debug code 2016-06-17 08:11:37 +02:00
bergquist
8b2f6fffc9 test(dashboards): comment code in broken tests 2016-06-17 07:43:57 +02:00
Torkel Ödegaard
32479503bd fix(build): another windows build issue 2016-06-16 21:10:30 +02:00
Torkel Ödegaard
b06ec734f1 fix(build): windows, another windows build fix, #5370 2016-06-16 18:21:12 +02:00
Torkel Ödegaard
b039a81375 feat(build): fixing windows build issue, #5370 2016-06-16 14:36:19 +02:00
Joel Smith
46fe9a167e Update file_export.ts (#5325)
Prepended first line to export file containing
`sep=;\n`
which I believe should be all that is required for Excel to interpret the CSV file as semicolon delimited.
2016-06-16 14:27:00 +02:00
Torkel Ödegaard
79eb971fad docs(): updated changelog 2016-06-16 10:49:40 +02:00
Torkel Ödegaard
81e9aa4de4 feat(datasource): cancel in flight data source requests, refeatoring #5321 2016-06-16 10:48:26 +02:00
Torkel Ödegaard
6d3521c240 Merge branch 'cancel-in-flight-repeats' of https://github.com/stuartnelson3/grafana into stuartnelson3-cancel-in-flight-repeats 2016-06-16 08:57:31 +02:00
Torkel Ödegaard
23e0240410 fix(build): removed logging call that caused wrong dependency to be used 2016-06-16 08:55:36 +02:00
Torkel Ödegaard
1ae24b366f feat(profiler): fixed issues with frontend perf profiler 2016-06-16 08:28:50 +02:00
Torkel Ödegaard
2ceb58d0c4 feat(elasticsearch): removed dashboard import migration 2016-06-16 08:11:40 +02:00
Torkel Ödegaard
e1f63a3346 docs(): updated changelog 2016-06-16 08:10:15 +02:00
Torkel Ödegaard
ec0b09450c Merge branch 'export-dashboard'
Conflicts:
	conf/defaults.ini
	pkg/setting/setting.go
	public/app/core/components/grafana_app.ts
	public/app/core/core.ts
	public/app/features/dashboard/dashboardCtrl.js
2016-06-16 08:06:43 +02:00
Torkel Ödegaard
4b78ab5bcd feat(graph): graph tooltip sort order PR refactored/changed #4944, changed the layout graph display options, #4944 2016-06-15 17:20:55 +02:00
Torkel Ödegaard
ae554a736b change(graphite): removed graphite png option in graph panel, closes #5367 2016-06-15 14:20:44 +02:00
Carl Bergquist
f842e28b85 Merge pull request #5343 from utkarshcmu/opentsdb-template
Implemented nested template variables functionality for Opentsdb
2016-06-14 07:43:41 +02:00
utkarshcmu
33aa3f0fc5 Made tag_values query more robust 2016-06-13 14:21:46 -07:00
utkarshcmu
e4e042e389 CHANGELOG entry 2016-06-13 04:53:21 -07:00
utkarshcmu
f3003a97ef Added required documentation 2016-06-13 04:34:23 -07:00
utkarshcmu
6550bc97ba Added unit tests 2016-06-13 04:24:27 -07:00
utkarshcmu
862de3a9dc Added templated dependency in Opentsdb 2016-06-13 03:59:12 -07:00
bergquist
22407fc897 fix(metrics): 64bit aligns standardcounter
Due to a bug in golang the 64bit variable i
need to come first to be 64bit aligned.
https://golang.org/pkg/sync/atomic/#pkg-note-BUG

closes #5341
2016-06-13 06:56:16 +02:00
Carl Bergquist
dba6fe8af3 Merge pull request #5340 from hailthemelody/master
update pricing to include 1 million free API requests per month
2016-06-13 06:54:00 +02:00
hailthemelody
ef9500a8f0 update pricing to include 1 million free API requests per month 2016-06-12 11:41:43 -04:00
Torkel Ödegaard
bf1ea560e9 feat(logging): error logging improvements 2016-06-11 12:16:33 +02:00
Torkel Ödegaard
086b59483e feat(loggin): disable logging by default so unit tests are not full of logging 2016-06-11 11:38:25 +02:00
stuart nelson
048bcf19f6 Use panel+ref for unique id
Previously, if a user changed the query between
requests, the previous query would not be
canceled. This handles that edge-case.
2016-06-09 15:17:17 +02:00
stuart nelson
8797be9f89 Add existence check for canceler. 2016-06-09 15:16:53 +02:00
stuart nelson
cc64d65c2f Rename cacheKey to exprID/requestID
Depending on context in the code, rename cacheKey
to exprID when it identifies a unique expression,
and rename cacheKey to requestID when it is
identifying a request.
2016-06-09 12:57:55 +02:00
stuart nelson
efdb990e56 Return an error for a canceled request.
Allow the datasource to decide how to handle a
canceled request.
2016-06-09 12:13:17 +02:00
stuart nelson
bc7c2cd3f5 Create cacheKey at top-level
Responsibility is now to pass the cacheKey through
to `datasourceRequest` in each datasources'
implementation of `query`.
2016-06-09 11:36:46 +02:00
Torkel Ödegaard
1584dac00a Merge branch 'master' of github.com:grafana/grafana 2016-06-09 10:43:46 +02:00
Torkel Ödegaard
79986e5593 Merge branch 'query-part-refactor'
Conflicts:
	public/app/plugins/datasource/influxdb/query_part.ts
2016-06-09 10:43:07 +02:00
Torkel Ödegaard
b8aa8b3079 feat(prometheus): restore old prometheus query editor, revert this commit in prometheus query editor v2 branch 2016-06-09 10:37:33 +02:00
Mark Baas
ced3bafa99 returns correct index (#5275) 2016-06-09 08:13:31 +02:00
Mukesh
755ec552de Bugfix: org select btn was not working on profile (#5317) 2016-06-09 00:43:38 +02:00
stuart nelson
18f9f6c159 Add in-flight identifier for Prometheus requests
Repeat Prometheus requests with the same query
will cancel preceding requests.
2016-06-08 18:05:46 +02:00
stuart nelson
6da7ed9706 Add support for canceling in-flight requests
Repeat requests, if they already exist in the
in-flight request map, will cause the previous
request to cancel.

The implementation of the unique key is the
responsibility of individual datasources.
2016-06-08 18:04:31 +02:00
bergquist
ffac5c1299 docs(changelog): add note about changelog 2016-06-08 09:35:34 +02:00
Carl Bergquist
fe5673134f Merge pull request #5292 from Thib17/master
Enable the "limit" param in /api/search
2016-06-08 09:19:58 +02:00
Torkel Ödegaard
1d8fdc09e7 feat(logging): added log format option, #4590 2016-06-08 08:48:46 +02:00
Torkel Ödegaard
7d6cda4916 Merge branch 'master' of github.com:grafana/grafana 2016-06-08 08:10:22 +02:00
Torkel Ödegaard
b25cb60259 Merge branch 'new-logger'
Conflicts:
	CHANGELOG.md
2016-06-08 08:09:59 +02:00
Torkel Ödegaard
87e98f01cd feat(logging): updated syslog writer to work with log15 log interface, closes #4590 2016-06-08 08:09:29 +02:00
Karl
22cda198ae Apply EscapeFilter to username to address grafana/grafana#5121 (#5279) 2016-06-08 07:28:16 +02:00
Tom Hukins
d1c06a93df Fix a typo (#5306) 2016-06-08 07:27:52 +02:00
Torkel Ödegaard
eed0d9c8d2 feat(graph performance): graph performance tweaks, refactoring #5297 2016-06-08 07:23:44 +02:00
Torkel Ödegaard
bf82fdb678 Merge branch 'perf_graph_js' of https://github.com/mtanda/grafana into mtanda-perf_graph_js 2016-06-08 06:53:28 +02:00
Torkel Ödegaard
e1e7fbf83d Merge branch 'master' of github.com:grafana/grafana 2016-06-08 06:51:43 +02:00
Torkel Ödegaard
c739428c30 feat(profiling): refactorign profiling code, #5286 2016-06-08 06:51:10 +02:00
Torkel Ödegaard
2a7d2ffccb Merge branch 'profiling_in_dev' of https://github.com/mtanda/grafana into mtanda-profiling_in_dev 2016-06-08 05:47:30 +02:00
Zdenek Styblik
5eceabf810 fix(): Check Organization exists before User is added (#5302)
Commit adds a check whether Organization exists before User is added to
the organization.

Fixes #3151.
2016-06-08 05:46:21 +02:00
Torkel Ödegaard
67ad903556 feat(test metrics): fixed issue with built in Grafana test data source, fixes #5299 2016-06-08 05:45:13 +02:00
Torkel Ödegaard
36b0802789 fix(png): fixed issue with png rendering, fixes #5274 2016-06-08 05:29:38 +02:00
Torkel Ödegaard
93fdc18fd4 feat(logging): fixed dependencies 2016-06-07 15:59:50 +02:00
Torkel Ödegaard
73b0e6c37b feat(logging): disable migrator logging during test 2016-06-07 15:50:16 +02:00
Torkel Ödegaard
65aad44464 feat(logging): added uname to context logger 2016-06-07 12:20:46 +02:00
Torkel Ödegaard
a02cf5beb7 feat(logging): added loging filters 2016-06-07 12:11:41 +02:00
bergquist
b76b42f209 docs(changelog): add note about deb post install script 2016-06-07 12:09:56 +02:00
Carl Bergquist
ee88b0dc35 Merge pull request #5282 from nazco/patch-1
restart grafana after upgrade
2016-06-07 12:03:42 +02:00
Torkel Ödegaard
3dc7706c45 feat(loggin): improved http request panic handling 2016-06-07 10:05:10 +02:00
Torkel Ödegaard
9741af2031 feat(logging): progress on new logging #4590 2016-06-07 09:29:47 +02:00
Mitsuhiro Tanda
487b2089a9 cache label width 2016-06-07 14:28:08 +09:00
Mitsuhiro Tanda
b28368c859 cache panel width 2016-06-07 14:04:06 +09:00
Torkel Ödegaard
22778e6efd feat(logging): a lot of progress on moving to new logging lib, #4590 2016-06-06 23:06:44 +02:00
Thibault Chataigner
3d77685108 Enable the "limit" param in /api/search 2016-06-06 16:15:20 +00:00
Mitsuhiro Tanda
25899b72d2 use applyAsync for compile (#5287) 2016-06-06 17:18:18 +02:00
Mitsuhiro Tanda
f877afb74d use async apply (#5258) 2016-06-06 17:18:10 +02:00
Mitsuhiro Tanda
83c76981b2 fix profiling code 2016-06-06 17:42:11 +09:00
Mitsuhiro Tanda
975b53b318 enable profiling in development mode 2016-06-06 17:42:11 +09:00
Karl
2f5ae85d33 Initial patch for grafana/grafana#4267 (#5280) 2016-06-06 07:15:37 +02:00
Ben Oswald
51878aeca8 change start to restart also for systemctl
I've forgotten to update the systemctl start to restart in my first commit
2016-06-05 16:27:57 +02:00
Ben Oswald
1d2eb0f903 restart grafana after upgrade
The current script only tries to start the already running grafana process after an upgrade. This leads to errors due to changed js and css hashes while grafana is delivering the old ones. To load the new sources we need to restart grafana after an upgrade.
2016-06-05 16:19:53 +02:00
Torkel Ödegaard
7cbaf06097 feat(instrumentation): check if enabled in http api metrics route 2016-06-03 21:22:34 +02:00
Torkel Ödegaard
1059a35bbc feat(instrumentation): documented instrumentation options, closes #4696 2016-06-03 18:38:19 +02:00
Torkel Ödegaard
064e474b0a Merge branch 'metrics_reporting' 2016-06-03 18:06:41 +02:00
Torkel Ödegaard
aef2b6b45f feat(instrumentation): finial polish 2016-06-03 17:15:17 +02:00
Torkel Ödegaard
35a7a3a52b feat(instrumentation): added some more timers 2016-06-03 17:00:39 +02:00
Torkel Ödegaard
e0c6048820 feat(instrumentation): added gauge and http endpoint 2016-06-03 16:15:36 +02:00
Torkel Ödegaard
ffb12d122f Update ISSUE_TEMPLATE.md 2016-06-03 15:34:08 +02:00
bergquist
b08f8bab71 Merge branch 'dakerfp-patch-3' 2016-06-03 15:09:18 +02:00
Torkel Ödegaard
1a05ae2eaa feat(instrumentation): more work 2016-06-03 15:06:57 +02:00
bergquist
961c31a747 test(util): add unit test for string util 2016-06-03 15:06:54 +02:00
bergquist
d1a345bb03 Merge branch 'patch-3' of https://github.com/dakerfp/grafana into dakerfp-patch-3 2016-06-03 15:02:46 +02:00
Carl Bergquist
236aed112f Merge pull request #5255 from dakerfp/patch-1
Unify signal registration in a single syscall.
2016-06-03 14:59:42 +02:00
bergquist
3d7facf6ee fix(cli): fixes broken import 2016-06-03 13:40:48 +02:00
Torkel Ödegaard
eee49a4995 feat(instrumentation): added meter, histogram and new timer, timer now send p25, p75, p90, p99 percentiles in 1000 sample exp decaying sample 2016-06-03 12:50:51 +02:00
bergquist
6de1399cf0 fix(cli): fixes broken import 2016-06-03 12:35:17 +02:00
bergquist
15aeb4aec2 tech(cli): rename log to logger to separate from server logger 2016-06-03 12:22:30 +02:00
Torkel Ödegaard
86f0007768 feat(instrumentation): added influxdb client 2016-06-03 09:18:21 +02:00
Torkel Ödegaard
3065d10931 feat(timing): timing is now working with graphite and influxdb 2016-06-03 09:17:36 +02:00
Torkel Ödegaard
4c4189d631 Update ISSUE_TEMPLATE.md 2016-06-03 08:38:48 +02:00
Torkel Ödegaard
015b409f2f Update ISSUE_TEMPLATE.md 2016-06-03 08:38:07 +02:00
Torkel Ödegaard
e2c794ff31 feat(instrumentation): lots of refactoring to support tag based backend, #4696 2016-06-02 21:06:49 +02:00
Torkel Ödegaard
2a9b51d836 feat(instrumentation): influxdb is working, now need to find a way to better support tags, #4696 2016-06-02 16:56:07 +02:00
bergquist
510360a509 docs(elastic): updates readme 2016-06-02 14:56:31 +02:00
Torkel Ödegaard
6b2a4fe8e8 feat(instrumentation): work on settings model for internal metrics publishing, #4696 2016-06-02 14:32:17 +02:00
Torkel Ödegaard
49fe90874a Merge branch 'v3.0.x' 2016-06-02 12:09:10 +02:00
Torkel Ödegaard
acbaef1907 fix(influxdb): fixed issue with backslash escaping in tag filter, fixes #5249 2016-06-02 12:08:13 +02:00
Torkel Ödegaard
74101eaf7c feat(instrumentation): changed name to senders 2016-06-02 12:04:50 +02:00
Torkel Ödegaard
8ab324988c Merge branch 'v3.0.x' 2016-06-02 09:57:20 +02:00
Torkel Ödegaard
1283461b89 fix(gzip): add plugin proxy to gzip exclusion, fixes #5237 2016-06-02 09:56:53 +02:00
Torkel Ödegaard
38790e2c4b fix(elasticsearch): fixed templating lucene / json escaping issue, fixes #5228, fixes #5227 2016-06-02 09:54:28 +02:00
Carl Bergquist
aa718b4dce Merge pull request #5253 from minkikim89/fix_seperate_typo
fixed separate typo
2016-06-02 07:42:04 +02:00
Daker Fernandes Pinheiro
2d09dfd34f Using variadic argument to StringFallback implementation 2016-06-02 01:46:18 -03:00
Daker Fernandes Pinheiro
48e4de823a Unify signal registration in a single syscall. 2016-06-02 01:34:37 -03:00
bergquist
65d8403a04 fix(metrics_reporting): adds missing formating varialbe 2016-06-01 15:16:17 +02:00
bergquist
a8ac37f517 feat(usage_metrics): add timer metrics 2016-06-01 15:04:58 +02:00
bergquist
b2c0679a7f feat(metrics): initial graphite metrics writer for internal stats 2016-06-01 13:31:11 +02:00
Carl Bergquist
8db00073b4 Merge pull request #5232 from peggyl/peggyl/fix-tags-popover-text
Fix wording of the dashboard tags popover text
2016-05-31 19:47:24 +02:00
Peggy Li
d36c1769e0 Fix wording of the dashboard tags popover text 2016-05-31 17:29:31 +00:00
Carl Bergquist
53ecb4c1ae Merge pull request #5222 from akiomik/patch-1
Fixed assets urls in 500.html
2016-05-31 07:59:24 +02:00
Akiomi KAMAKURA
616dd5c4a5 Fixed assets urls in 500.html 2016-05-31 14:26:13 +09:00
bergquist
2edb0ad94d feat(influxdb): adds spread functionallity
closes #5211
2016-05-30 14:23:24 +02:00
Carl Bergquist
f8a535c6e8 Merge pull request #5195 from matschaffer/cloudwatch_metric_update_elasticbeanstalk
Add metrics for AWS/ElasticBeanstalk
2016-05-30 08:05:09 +02:00
Carl Bergquist
f1bd614770 Merge pull request #5183 from nfnty/master
package.json: Upgrade grunt-contrib-compress, Fixes #5071
2016-05-30 08:02:00 +02:00
Torkel Ödegaard
c8965d0f9a feat(export): export will add templatize constant variables 2016-05-28 20:27:44 +02:00
Torkel Ödegaard
53bb264375 Merge branch 'master' into export-dashboard 2016-05-28 17:17:51 +02:00
Torkel Ödegaard
1ea54049d0 feat(templating): added new template variable type constant 2016-05-28 16:59:29 +02:00
Torkel Ödegaard
ca8543348b docker(): added collectd system metrics collector that writes to graphite, just for testing 2016-05-28 10:13:51 +02:00
hc4
cf87e8ecf5 Fix parsing of intervals. defined in ms (#5151)
* Fix parsing of intervals. defined in ms

Fix parsing of intervals. defined in ms.
Increase accuracy for sub-second inrevals.
Closes #5008

* Tests for sub-ms intervals

Unit test for 2034d4b971
2016-05-27 17:26:20 +02:00
Carl Bergquist
a6afd85526 Merge pull request #5197 from minkikim89/fixtypo
Fixed type
2016-05-27 16:57:07 +02:00
Torkel Ödegaard
0d4c76a029 feat(import): save gnetId for dashbards imported from grafana.net 2016-05-27 16:42:32 +02:00
Torkel Ödegaard
c3708b3096 feat(import): import directly from grafana.net id/url now works 2016-05-27 16:11:05 +02:00
Torkel Ödegaard
22a7eaf2e7 Merge branch 'master' into export-dashboard 2016-05-27 13:52:53 +02:00
Torkel Ödegaard
540def2c39 feat(import): working on unit tests for import ctrl 2016-05-27 13:52:19 +02:00
Torkel Ödegaard
bf90fbc678 fix(templating): fixed failing templating unit test 2016-05-27 09:23:08 +02:00
Tim Bielawa
2b9d260686 docs(rebuild): Include new http api preferences docs in menus (#5194)
This updates the mkdocs.yml source file such that the HTTP Preferences
API is included in the website navigation bar and in the HTTP API
overview page.

This commit also refreshes the docs/README.md file with more verbose
instructions for building and viewing the documentation locally.

* Original issue: #5069 Document org & user preferences HTTP docs
* Original PR: #5087

Closes #5193
2016-05-27 08:58:42 +02:00
Torkel Ödegaard
f6633c8189 feat(export): minor dupe fix 2016-05-27 08:34:12 +02:00
Mat Schaffer
18f704533f Add enhanced elasticbeanstalk metrics 2016-05-27 11:47:53 +09:00
Mat Schaffer
aedba5411c Add basic metrics for AWS/ElasticBeanstalk 2016-05-27 11:30:16 +09:00
Torkel Ödegaard
e83d13848e Merge branch 'master' into export-dashboard
Conflicts:
	public/app/features/dashboard/submenu/submenu.ts
2016-05-26 14:22:22 +02:00
Torkel Ödegaard
696fad702f Merge branch 'v3.0.x'
Conflicts:
	public/app/features/templating/templateValuesSrv.js
2016-05-26 14:21:17 +02:00
Torkel Ödegaard
724a511995 fix(templating): fixed issue with value being shown instead of it's text representation, fixes #5172 2016-05-26 13:18:02 +02:00
Torkel Ödegaard
90c9c70416 fix(): another fix for panel image rendering 2016-05-26 08:49:55 +02:00
Torkel Ödegaard
f8a4661d05 Merge branch 'master' of github.com:grafana/grafana 2016-05-26 08:37:19 +02:00
Torkel Ödegaard
dd494e648a fix(rendering): fixed issue with phantomjs panel rendering 2016-05-26 07:45:53 +02:00
Jared Wiltshire
c9d6321f38 Allow for proxying Authorization header and automatically convert (#4832)
Authorization header to X-DS-Authorization in backend_srv.js
2016-05-26 07:13:29 +02:00
Mukesh
4038b4d17e Set active org through admin api (#5179) 2016-05-26 06:51:23 +02:00
nfnty
46551e9d65 package.json: Upgrade grunt-contrib-compress, Fixes #5071 2016-05-26 01:03:22 +02:00
Torkel Ödegaard
1060eeb197 feat(dashboard): include org id query parameter in dashboard url, #1613 2016-05-25 17:06:41 +02:00
Torkel Ödegaard
201d30a944 fix(export): style fixes and markup fixes for share modal 2016-05-25 13:01:40 +02:00
Torkel Ödegaard
fc2a069180 feat(export): fixed refactoring issue with dynamic dashbord srv 2016-05-25 12:45:52 +02:00
Torkel Ödegaard
392407136d Merge branch 'export-dashboard' of github.com:grafana/grafana into export-dashboard 2016-05-25 12:33:30 +02:00
Torkel Ödegaard
ba6573af61 Merge branch 'master' into export-dashboard
Conflicts:
	public/app/features/dashboard/submenu/submenu.ts
2016-05-25 12:32:56 +02:00
Matt Toback
8d988f9582 Export dashboard bulletfactory (#5160)
* create descriptions and styles for share dropdown

* Updating actual modal layout for Sharing

* Updated the modals to follow the new styles, fixed the wrapping issue on the main menu. Standardized buttons.
2016-05-25 12:30:27 +02:00
Torkel Ödegaard
f923edc424 Merge branch 'v3.0.x' 2016-05-25 12:29:35 +02:00
Torkel Ödegaard
2712d9ae8b Update latest.json 2016-05-25 12:23:32 +02:00
Torkel Ödegaard
3312a042dd docs(): updated download links 2016-05-25 11:50:00 +02:00
Torkel Ödegaard
5040570ea9 docs(): updated changelog 2016-05-25 11:07:29 +02:00
Torkel Ödegaard
f5c5d1b1da Merge branch 'master' of github.com:grafana/grafana 2016-05-25 11:04:27 +02:00
Torkel Ödegaard
2cd6c2e7e0 Merge branch 'v3.0.x' 2016-05-25 11:04:12 +02:00
Torkel Ödegaard
0daadc954c fix(templating): fixed issue with detecting data source variable in other template variable definition, fixes #5165 2016-05-25 10:46:55 +02:00
bergquist
ec98b7d672 docs(changelog): add note about fix for 5167 2016-05-25 10:01:49 +02:00
bergquist
8c2b6b532d fix(preferences): fixes broken default home dashboard
closes #5167
2016-05-25 09:56:45 +02:00
Torkel Ödegaard
71d62012e1 fix(panel): fixed issue with fullscreen panel view and switching to another dashboard, fixes #5163 2016-05-25 09:46:15 +02:00
Torkel Ödegaard
41deea90ee feat(dashboard): template variable changes updates url, closes #5002 2016-05-24 16:34:17 +02:00
Torkel Ödegaard
a81806d3d0 feat(dashboard): sync time range with url, closes #458 2016-05-24 16:32:28 +02:00
Torkel Ödegaard
5607a114f9 updated changelog 2016-05-24 09:53:28 +02:00
Torkel Ödegaard
e81614b9e9 Merge branch 'v3.0.x' 2016-05-24 09:50:41 +02:00
Torkel Ödegaard
6f094ef215 fix(templating): fixed issue with nested template variables and multi select, the child variable selection state is now updated like single select variables, so if none matches the first option is selected, fixes #4861 2016-05-24 09:50:23 +02:00
Torkel Ödegaard
366baea099 docs(): updated changelog 2016-05-24 08:14:40 +02:00
Torkel Ödegaard
dc9dcd045d Merge branch 'master' of github.com:grafana/grafana 2016-05-24 08:11:52 +02:00
Torkel Ödegaard
10c47ee27c feat(footer): some minor changes to footer to make it look good in light theme, closes #4889 2016-05-24 08:11:28 +02:00
Torkel Ödegaard
8f0240a295 Merge branch 'footer' 2016-05-24 07:53:13 +02:00
Torkel Ödegaard
fd08c821f9 Merge branch 'v3.0.x'
Conflicts:
	package.json
2016-05-24 07:52:27 +02:00
Torkel Ödegaard
c41c771e9a fix(home dashboard): fixed handling error when default dashboard is not found, fixes #5141 2016-05-24 07:39:58 +02:00
Zdenek Styblik
fff5aa3020 Add missing option Read-Only Editor to auto_assign_org_role description (#5139)
Commit adds missing option `Read-Only Editor` to `auto_assign_org_role` description.
2016-05-23 21:24:23 +02:00
Torkel Ödegaard
f1ec270e3e bumped version to 3.0.4 2016-05-23 21:24:02 +02:00
Torkel Ödegaard
a3f2f574c6 fix(singlestat): fixed Gauge positioning issue, fixes #5143 2016-05-23 21:23:31 +02:00
Utkarsh Bhatnagar
ec19a97156 [Bug Fix] #5136 (#5142) 2016-05-23 21:00:06 +02:00
Torkel Ödegaard
9a7817a271 Merge branch 'master' into footer
Conflicts:
	pkg/api/frontendsettings.go
2016-05-23 20:59:23 +02:00
Utkarsh Bhatnagar
8a0d5aa38d [Bug Fix] #5136 (#5142) 2016-05-23 20:58:21 +02:00
Trent White
a52869507e hide footer on non-dashboard pages 2016-05-23 12:46:13 -04:00
Torkel Ödegaard
c77d72b29f feat(prometheus): progress on new prometheus query editor, #5117 2016-05-23 18:03:17 +02:00
Trent White
76d18e7156 remove height: 100% on .main-view 2016-05-23 11:45:54 -04:00
Torkel Ödegaard
9e6056551d docs(): updated download links 2016-05-23 14:13:30 +02:00
Torkel Ödegaard
bbea698af3 Update latest.json 2016-05-23 12:30:46 +02:00
Torkel Ödegaard
9eec68985d docs(): updated download links 2016-05-23 11:49:07 +02:00
Torkel Ödegaard
cd82f579bd docs(): updated changelog 2016-05-23 11:08:08 +02:00
Torkel Ödegaard
93665f49b1 Merge branch 'v3.0.x' 2016-05-23 11:06:53 +02:00
Torkel Ödegaard
dc77d555f9 fix(elasticsearch): fixed templating issue with elasticsearch, fixes #5135 2016-05-23 10:58:31 +02:00
Torkel Ödegaard
dfe3806d01 fix(elasticsearch): fixed query editor issue with elasticsearch 2016-05-23 10:14:40 +02:00
Torkel Ödegaard
cfc7710205 docs(): changelog updated 2016-05-23 09:31:52 +02:00
Torkel Ödegaard
c60d737928 Merge branch 'v3.0.x'
Conflicts:
	package.json
2016-05-23 09:29:14 +02:00
Torkel Ödegaard
1da149d9e1 feat(annotations): annotations can now use a template variable as data source, closes #5054 2016-05-23 09:28:14 +02:00
Torkel Ödegaard
43ba563a1c fix(logging): change log level to trace for plugin proxy logging call, fixes #5126 2016-05-23 07:55:55 +02:00
minki
05cb6048ae fixed separate typo 2016-05-23 09:32:18 +09:00
minki
70d6b32e14 Fixed type 2016-05-22 05:38:57 +09:00
Trent White
75940c1f5d turn watch all back on 2016-05-21 13:21:31 -04:00
Mitsuhiro Tanda
1d27a7f93d (cloudwatch) fix wrong cache key of credentials (#5124) 2016-05-21 09:02:04 +02:00
Trent White
cffcc4c7a5 make footer unordered list. add new icons. 2016-05-20 16:44:19 -04:00
Trent White
c727c3c441 resize and color of links 2016-05-20 15:58:14 -04:00
Torkel Ödegaard
fb4dc77f36 docs(): updated changelog with 3.0.3 fixes 2016-05-20 15:26:19 +02:00
Torkel Ödegaard
9eb7b192b8 Merge branch 'master' of github.com:grafana/grafana 2016-05-20 15:16:05 +02:00
Torkel Ödegaard
06d63dda6e Merge branch 'v3.0.x' 2016-05-20 15:15:30 +02:00
Torkel Ödegaard
e6f251011f fix(panel span): fixed issue setting panel span while in fullscren and also an issue when changing repeat variable while in fullscreen view, fixes #4957 2016-05-20 15:15:02 +02:00
Torkel Ödegaard
6a813aa33d fix(export): better error handling 2016-05-20 14:45:22 +02:00
David J. Felix
441682b598 Fix linking for /dashboard-solo/ proxy prefix (#5116)
Fixes #5109
2016-05-20 14:01:12 +02:00
Mitsuhiro Tanda
9c672f6ec1 (prometheus) support new legend format (with backward compatibility) (#5096)
* (prometheus) support new legend format (with backward compatibility)

* (prometheus) use regex replace for legend format

* (prometheus) allow white space
2016-05-20 12:29:10 +02:00
Torkel Ödegaard
35c05463e7 Merge branch 'v3.0.x' 2016-05-20 12:23:50 +02:00
Torkel Ödegaard
f00cbc0aeb fix(panel height): fixed issue with singlestat height, fixes #4679, fixes #4894, fixes #5113 2016-05-20 12:23:26 +02:00
Torkel Ödegaard
ee86d24797 fix(elasticsearch): minor editor layout fix 2016-05-20 10:31:22 +02:00
Torkel Ödegaard
58a9324db0 Merge branch 'v3.0.x' 2016-05-20 10:24:54 +02:00
Torkel Ödegaard
e0e8fd6637 fix(templating): fixed handling of numeric values in tempalting query results, fixes #5097 2016-05-20 10:24:24 +02:00
Torkel Ödegaard
2416ee04c8 fix(templating): fixed detection of nested template variables, fixes #5103 2016-05-20 09:58:07 +02:00
Torkel Ödegaard
91c6ebb06c Merge branch 'v3.0.x' 2016-05-20 09:06:39 +02:00
Torkel Ödegaard
df0ddc0b50 fix(prometheus): fixed bug in prometheus query editor, fixes #5107 2016-05-20 09:03:52 +02:00
Torkel Ödegaard
2e02abffc0 fix(render): fixed issue with image renderer caused by disabling angular debug info 2016-05-20 08:34:35 +02:00
Torkel Ödegaard
e47957ce6d Merge branch 'master' of github.com:grafana/grafana 2016-05-20 08:32:40 +02:00
Torkel Ödegaard
c54e688272 Merge branch 'v3.0.x' 2016-05-20 08:31:51 +02:00
Torkel Ödegaard
37821e6d63 fix(share modal): fixed link in share modal when sub app url is /dashboard/, fixes #5109 2016-05-20 08:31:27 +02:00
Torkel Ödegaard
a3ee388b66 Merge branch 'master' into query-part-refactor 2016-05-19 14:52:18 +02:00
Torkel Ödegaard
855e913bbd feat(dashboards): began work on dashboard list 2016-05-19 11:03:10 +02:00
Richard Hartmann
78360ece8a ISSUE_TEMPLATE.md: Improve wording and fix typos (#5101) 2016-05-19 10:59:38 +02:00
Richard Hartmann
7c46423727 ISSUE_TEMPLATE.md: Fix typo (#5099) 2016-05-19 10:34:12 +02:00
Torkel Ödegaard
fb74d10573 feat(export): added grafana version to requires array, #5084 2016-05-19 10:21:16 +02:00
Torkel Ödegaard
430bcf192f feat(export): templetize annotations and template vars, #5084 2016-05-19 10:01:31 +02:00
Torkel Ödegaard
cac723dab3 Merge branch 'master' into export-dashboard 2016-05-19 08:48:24 +02:00
bergquist
617d18e587 feat(panel): active tab is now placed in querystring aswell 2016-05-19 08:42:21 +02:00
bergquist
2b06ceda71 feat(panels): adds queryparameter for choose active tab in edit mode 2016-05-19 08:00:48 +02:00
Torkel Ödegaard
1bb4ca22e7 fix(test): fixed failing unsaved changes test 2016-05-19 07:58:44 +02:00
Tim Bielawa
24a410ae8f docs(preferences): Document user and org preferences (#5087)
closes #5069
2016-05-18 18:31:59 +02:00
Torkel Ödegaard
673984a7db feat(export): more export stuff 2016-05-18 15:53:13 +02:00
Torkel Ödegaard
10339090b8 fix(annotations): fixed annotation error handling, fixes #5077 2016-05-18 15:22:40 +02:00
Torkel Ödegaard
b6dcf6bd02 Merge branch 'v3.0.x' 2016-05-18 14:23:59 +02:00
Torkel Ödegaard
280e7bb04d Merge branch 'master' of github.com:grafana/grafana 2016-05-18 14:23:41 +02:00
Torkel Ödegaard
03551a5961 Merge remote-tracking branch 'origin/development' 2016-05-18 14:23:21 +02:00
Torkel Ödegaard
d474eba53a fix(logging): fixed reading config level from config file, fixes #5079 2016-05-18 14:18:08 +02:00
Mitsuhiro Tanda
392cb2a714 (cloudwatch) update changelog (#5080)
* update cloudwatch.md

* update changelog
2016-05-18 13:27:19 +02:00
bergquist
92ac370415 tech(docker): rename fake data writers 2016-05-18 12:29:37 +02:00
Torkel Ödegaard
c41e3dcb91 updated changelog 2016-05-18 12:04:37 +02:00
Torkel Ödegaard
602d1a5fbc Merge branch 'v3.0.x' 2016-05-18 12:02:53 +02:00
Torkel Ödegaard
cd80884b76 fix(dashboard timepicker): fixed issue with time picker and UTC when reading time from url, fixes #5078 2016-05-18 12:01:11 +02:00
Torkel Ödegaard
bfadc932d7 Merge branch 'master' of github.com:grafana/grafana 2016-05-18 11:50:56 +02:00
Torkel Ödegaard
0cd2e150d5 feat(snapshots): performance improvements to deep clone, makes snapshot's a lot quicker for big dashboards with a lot of panels and data 2016-05-18 11:50:40 +02:00
Carl Bergquist
5aaaeb05a0 Merge pull request #5075 from mtanda/prometheus_templating_fix
(prometheus) fix metric find query
2016-05-18 11:40:33 +02:00
Torkel Ödegaard
26ea0bc360 feat(export): work on export 2016-05-18 11:11:53 +02:00
Mitsuhiro Tanda
a86d218891 (prometheus) fix metric find query 2016-05-18 16:36:57 +09:00
Torkel Ödegaard
6632f883c0 Merge branch 'master' into export-dashboard
Conflicts:
	.floo
	.flooignore
2016-05-18 08:08:15 +02:00
Mitsuhiro Tanda
66bcae353c (prometheus) pass dashboard time range to template query (#5007)
* (prometheus) pass dashboard time range to template query

* (prometheus) add passing time test of templating
2016-05-18 07:56:23 +02:00
Mitsuhiro Tanda
07d355851e (cloudwatch) assume role support (#5065)
* (cloudwatch) assume role support

* save godep

* (cloudwatch) add assumeRoleArn field

* (cloudwatch) set cred provider for sts

* (cloudwatch) fix test
2016-05-18 07:54:24 +02:00
Mitsuhiro Tanda
8d2f350ad1 (prometheus) fix prometheus link 2016-05-18 07:50:30 +02:00
Mitsuhiro Tanda
fc1891320e (prometheus) fix prometheus link (#5074) 2016-05-18 07:49:32 +02:00
Utkarsh Bhatnagar
8a9455d901 Fixed singlestat mapping typo (#5070) 2016-05-18 07:44:01 +02:00
Torkel Ödegaard
46b6ab7db7 Merge branch 'master' of github.com:grafana/grafana 2016-05-17 21:51:31 +02:00
Torkel Ödegaard
958f97232f fix(pluginlist): fixed issue with plugin list, fixes #5068 2016-05-17 21:51:19 +02:00
Torkel Ödegaard
05d064ca8d export(): moved to share modal 2016-05-17 21:18:47 +02:00
Carl Bergquist
47f88346d2 Merge pull request #5058 from hijklmno/master
Add dBm as an option in energy units
2016-05-17 15:57:05 +02:00
bergquist
b5fc12fb80 docs(opentsdb): add working image of add datasource for opentsdb
closes #4984
2016-05-17 15:32:33 +02:00
Torkel Ödegaard
83f5080274 feat(angular): disable debug in production for angular compiler 2016-05-17 15:00:48 +02:00
Torkel Ödegaard
df50fa2332 feat(export): export dashboard modal 2016-05-17 11:17:11 +02:00
Torkel Ödegaard
ad7a1e15b4 feat(export): began working on export modal 2016-05-17 10:29:57 +02:00
bergquist
efe6fd154b tech(docker): add default writer for influxdb 2016-05-17 09:03:52 +02:00
bergquist
fb8296524e tech(docker): add default fake-data-gen for prometheus 2016-05-17 09:03:52 +02:00
Torkel Ödegaard
00957a42d4 Merge branch 'v3.0.x' 2016-05-17 08:40:28 +02:00
Torkel Ödegaard
99db89067e fix(): reverted RESTART_ON_UPGRADE change 2016-05-17 08:34:34 +02:00
hijklmno
f1b5a265ab fix trailing whitespace in kbn.js 2016-05-16 15:35:42 -07:00
hijklmno
451e917e7d Add dBm as an option in energy units 2016-05-16 15:24:31 -07:00
Torkel Ödegaard
d443079cf6 fix(): fixed sass issue 2016-05-16 18:48:13 +02:00
Torkel Ödegaard
163e55c0eb Update latest.json 2016-05-16 18:07:42 +02:00
Torkel Ödegaard
09f11cf66e updated 2016-05-16 14:11:55 +02:00
Torkel Ödegaard
4ea3002572 added floobits stuff 2016-05-16 14:02:34 +02:00
Torkel Ödegaard
840cd7b2e1 doc(): updated changelog 2016-05-16 13:58:38 +02:00
Torkel Ödegaard
0760528f4a Merge branch 'v3.0.x' 2016-05-16 13:57:44 +02:00
Torkel Ödegaard
7f0fe31881 docs(): updated download links 2016-05-16 13:41:50 +02:00
Torkel Ödegaard
2be8658034 Merge remote-tracking branch 'origin/development' 2016-05-16 11:40:12 +02:00
Torkel Ödegaard
494bee1d6b bumped version 2016-05-16 11:39:16 +02:00
bergquist
0c345e2b09 docs(changelog): remove invalid chars 2016-05-16 09:06:39 +02:00
Carl Bergquist
adce8c15bb Merge pull request #5041 from LindsayHill/patch-1
Fixed minor typo s/seperate/separate/
2016-05-15 22:25:15 +02:00
Torkel Ödegaard
7cd663bbe8 feat(import): more import work 2016-05-14 10:00:43 +02:00
Lindsay Hill
85758a2dd2 Fixed minor typo s/seperate/separate/
Fixed small typo in help text
2016-05-14 17:51:08 +12:00
Utkarsh Bhatnagar
7bc15ec6c1 [Bug Fix] Opentsdb Alias issue (#4910)
* Fixed Opentsdb Alias issue

* Fixed Opentsdb query editor
2016-05-13 22:22:56 +02:00
Torkel Ödegaard
d9d46096dd feat(import): lots of work on dashboard import 2016-05-13 17:39:22 +02:00
bergquist
da68f7d31a feat(docker): fake data writer for opentsdb 2016-05-13 16:53:28 +02:00
bergquist
41ed0e670a feat(docker): fake data writer for graphite 2016-05-13 16:25:03 +02:00
bergquist
579b36754a Merge branch 'master' into development 2016-05-13 14:30:47 +02:00
bergquist
e50211572f docs(changelog): add note about fix for graph panel 2016-05-13 13:54:39 +02:00
bergquist
6849bfae16 fix(graph): fixes broken hide xaxis option
closes #5024
2016-05-13 13:52:57 +02:00
bergquist
c3f1d1a647 fix(influxdb): fixes extra semi colon due to hidden series
closes #5005
2016-05-13 13:36:57 +02:00
bergquist
ac674bd405 docs(changelog): add note about graph fix 2016-05-13 12:23:58 +02:00
bergquist
d5899aacfb fix(graph-panel): fixes broken PNG rendering
When refactoring y-axies for graph panel these
was forgotten and which caused the graphite datasource
to send invalid data.

closes #5025
2016-05-13 12:20:39 +02:00
bergquist
9e5a8c3fc8 docs(changelog): add info about configurable theme 2016-05-13 11:38:54 +02:00
Carl Bergquist
83707f7b35 Merge pull request #5011 from acmnu/default_theme
Add new parameter to config: default_theme.
2016-05-13 11:36:32 +02:00
Torkel Ödegaard
ca8df67947 feat(import): things are starting to work 2016-05-13 11:26:02 +02:00
Prajwal Rao
3feb6492e6 fixed datasources icon (#5015) 2016-05-12 21:49:58 +02:00
Anton Chevychalov
c6744925c4 Add new parameter to config: default_theme. 2016-05-12 18:21:11 +03:00
bergquist
88b2f48493 Merge branch 'master' into development 2016-05-12 16:22:18 +02:00
Torkel Ödegaard
0d3e06e68a feat(wizard): merged wizard poc 2016-05-12 14:45:32 +02:00
Torkel Ödegaard
bf890719ff Merge remote-tracking branch 'origin/wizard' into export-dashboard2 2016-05-12 10:52:24 +02:00
Torkel Ödegaard
28eae1e7ff Merge branch 'master' into export-dashboard
Conflicts:
	packaging/publish/publish.sh
	public/app/features/dashboard/dynamicDashboardSrv.js
	public/test/specs/dynamicDashboardSrv-specs.js
2016-05-12 10:50:37 +02:00
Dan Cech
9f9f4e7fef use new plugin-specific repo route when installing or updating a single plugin (#4992) 2016-05-12 10:43:31 +02:00
Denny Schäfer
2f6b00b6f7 Add What's New in Grafana 3.0 link into the readme (#5001) 2016-05-12 10:41:36 +02:00
Torkel Ödegaard
35f55cabf0 fix(templating): improved detection of nested template variables, fixes #4986, fixes #4987 2016-05-12 10:41:15 +02:00
Torkel Ödegaard
0201ac24e7 fix(templating): fixed issue with mixing repeated row and repeated panel, fixes #4988 2016-05-12 10:31:36 +02:00
Torkel Ödegaard
731c35540f packaging(): default RESTART_ON_UPGRADE to true, closes #4993 2016-05-12 07:29:33 +02:00
Dan Cech
dac62ec560 fix rpm download link 2016-05-11 14:09:03 -04:00
Torkel Ödegaard
2c7447eaca feat(): started work on new import system 2016-05-11 16:18:52 +02:00
Torkel Ödegaard
b170b6ec8b feat(query part): moved query part editor from influxdb to core 2016-05-11 14:52:44 +02:00
Torkel Ödegaard
8a3bdb3685 fix(typo): corrected spelling in error message, fixes #4982 2016-05-11 13:21:25 +02:00
Torkel Ödegaard
85e8cba7a1 Merge branch 'master' of github.com:grafana/grafana 2016-05-11 13:20:14 +02:00
Torkel Ödegaard
56bf9c5612 fix(): changed how package iteration/build is generated 2016-05-11 13:20:01 +02:00
Torkel Ödegaard
549eb15c32 Update latest.json 2016-05-11 10:37:21 +02:00
Torkel Ödegaard
03663c5b28 docs(): updated download links 2016-05-11 10:23:17 +02:00
Torkel Ödegaard
bbd52c0b71 changelog(): updated and updated version 2016-05-11 09:36:07 +02:00
Trent White
995f6be2c4 old grafana wordmark was still showing on login and sidebar (#4972) 2016-05-11 09:08:25 +02:00
Torkel Ödegaard
5b42753b8b feat(export): progress on dashboard export 2016-05-10 21:09:15 +02:00
Torkel Ödegaard
959714a6ef feat(docs): updated what's new article 2016-05-10 20:33:42 +02:00
Torkel Ödegaard
79a8017fe9 feat(export): more progress on dashboard export 2016-05-10 20:31:47 +02:00
Carl Bergquist
e4a24e1785 Merge pull request #4969 from peggyl/peggyl/fix-update-checker-typo
Fix typo in error message from update checker
2016-05-10 18:17:09 +02:00
Peggy Li
9b0da20d90 Fix typo in error message from update checker 2016-05-10 16:06:51 +00:00
Torkel Ödegaard
db664c61a4 Merge branch 'master' into export-dashboard 2016-05-10 16:46:58 +02:00
Torkel Ödegaard
c299b86983 docs(): updated readme 2016-05-10 16:33:05 +02:00
Torkel Ödegaard
56e53d7da2 docs(): update readme dependency section 2016-05-10 16:07:59 +02:00
Torkel Ödegaard
d676840258 docs(): added homebrew info to mac install docs 2016-05-10 16:02:00 +02:00
Torkel Ödegaard
cca37caf33 feat(prometheus): began work on prometheus query model 2016-05-10 15:48:07 +02:00
Torkel Ödegaard
4358687bfa Merge branch 'master' into query-part-refactor 2016-05-10 14:38:49 +02:00
Torkel Ödegaard
ae66c3f289 fix(influxdb): minor editor display fix 2016-05-10 14:38:11 +02:00
Torkel Ödegaard
d3bbc245c9 feat(query_part): began query part refactor to be able to reuse it in prometheus query editor 2016-05-10 14:32:25 +02:00
bergquist
5ee1b6ca97 docs(changelog): add note about merged PR 2016-05-10 12:54:25 +02:00
Carl Bergquist
c522341136 Merge pull request #4944 from Gueust/optional_tooltip_ordering
Add optional tooltip ordering (against the development branch)
2016-05-10 12:51:44 +02:00
bergquist
2cebe151f2 Merge branch 'master' into development 2016-05-10 12:40:17 +02:00
Torkel Ödegaard
ecf5b61e86 Update ISSUE_TEMPLATE.md 2016-05-10 11:36:45 +02:00
Richard Hartmann
c01ab63744 ISSUE_TEMPLATE.md: different layout (#4960) 2016-05-10 11:33:33 +02:00
Torkel Ödegaard
72b324c95b fix(go16): fixed hang with go 1.6 by updating sqlite3, fixes #4367 2016-05-10 11:22:06 +02:00
minkikim89
0c5abc491d Update index.md (#4956) 2016-05-10 08:44:18 +02:00
LaszloHont
a5e2e59385 Clarify admin_password (#4948)
Closes #4923
2016-05-09 13:44:11 +02:00
Torkel Ödegaard
040dd91d2e fix(templating): fixed issue with current data source variable value, fixes #4934 2016-05-09 10:17:30 +02:00
Torkel Ödegaard
c6c07599c7 conf(): updated comments in config file, fixes #4933 2016-05-09 09:21:33 +02:00
Peggy Li
04ef25b6ff Set custom type for templating variables (#4941) 2016-05-07 07:58:01 +02:00
Carl Bergquist
05ca7158d6 Merge pull request #4886 from Gueust/contribute_doc
Add documentation on the build system for occasional contributors
2016-05-06 15:04:14 +02:00
Torkel Ödegaard
c7e7a0cd16 fix(singlestat): rerender singlestat and reevaluate thresholds on render, fixes #4920 2016-05-05 10:29:14 +02:00
Utkarsh Bhatnagar
70f7177025 Fixed deleting row bug (#4919) 2016-05-05 09:57:21 +02:00
Mathieu Payeur Levallois
c86cdb1805 opentsdb: apply templating on filters (#4594) 2016-05-04 13:47:05 +02:00
Torkel Ödegaard
bd15534360 fix(singlestat gauge): better font size handling for gauge, now value font size is used as scaling factor, fixes #4876 2016-05-04 11:46:21 +02:00
Carl Bergquist
e30745f19c Merge pull request #4881 from mmckinst/kairosdb_broken_image
fix broken link for kairosdb image
2016-05-04 11:05:05 +02:00
Idan Zalzberg
bca8d6d07b singlestat/module.ts onDataError was calling onDataReceived incorrectly (#4897)
onDataError was calling onDataReceived with {data : []} which breaks at the first line since object has no map function.
The correct form is probably just []
2016-05-04 10:48:01 +02:00
Martin Häger
0764a4313b AWS Elasticsearch Service Dimensions (#4903) 2016-05-04 10:47:35 +02:00
Denny Schäfer
e0ef6dd8d4 Fix changelog formatting for 3.0.0-beta7 (#4905) 2016-05-04 10:47:17 +02:00
bergquist
3d366c2a4c feat(graphs): align forms for line mode checkbox 2016-05-04 10:42:12 +02:00
Carl Bergquist
2018e30366 Merge pull request #4902 from idanz/patch-4
Bring back threshold line mode
2016-05-04 10:39:36 +02:00
fg2it
303cd8a5af [RenderToPng fix] (#4901)
* removing useless code

* fix various minor typo

* don't silence phantomjs timeout and allow more time

* fix gofmt
2016-05-04 09:07:45 +02:00
Idan Zalzberg
2f7af968bf Bring back threshold line mode
Threshold line mode was somehow discarded from the HTML in the ui redesign, this brings it back
2016-05-04 10:04:00 +07:00
Matt Toback
543d247af8 Wrapped the form in a form tag and added a submit, the ng-click shoudl work the same, but now enter works. @torkelo, pls review (#4898) 2016-05-03 21:02:57 +02:00
Jean-Baptiste Lespiau
ca1182e783 Stress the required version of node JS 2016-05-03 19:10:32 +02:00
Jean-Baptiste Lespiau
a34a784b43 Add more documentation on how to contribute
Add more documentation on how to fork the project, and how to
build on changes using grunt
2016-05-03 19:10:31 +02:00
Torkel Ödegaard
3bd4b5ccc6 Merge branch 'master' of github.com:grafana/grafana 2016-05-03 19:00:57 +02:00
Torkel Ödegaard
f4a013946f feat(pluginlist): link in plugin list now goes to app/plugin default nav unless enabled 2016-05-03 19:00:42 +02:00
Matt Toback
d2fd829a58 Update module.html 2016-05-03 12:42:37 -04:00
Torkel Ödegaard
bb6f4fff87 feat(export/import): minor progress 2016-05-03 16:40:21 +02:00
Torkel Ödegaard
5ffd57695c feat(table): added support for column units overriding style units for table 2016-05-03 11:29:51 +02:00
bergquist
02ae1f79f7 docs(changelog): add node about range to text mappings in singlestat 2016-05-03 10:42:01 +02:00
Torkel Ödegaard
f42b47e65b Merge branch 'master' into export-dashboard
Conflicts:
	public/app/features/dashboard/dashnav/dashnav.ts
2016-05-03 10:26:40 +02:00
Torkel Ödegaard
6dc24ab2d7 Merge branch 'master' of github.com:grafana/grafana 2016-05-03 10:25:16 +02:00
Torkel Ödegaard
fe0b7533a1 fix(influxdb): quote number valued tag values, only not quote when operator is > or <, fixes #4885 2016-05-03 10:25:06 +02:00
Utkarsh Bhatnagar
b8d861edc1 Fixed query editor UI for keywords (#4890) 2016-05-03 10:09:03 +02:00
Torkel Ödegaard
de26a17dc7 feat(footer): began work on page footer 2016-05-03 09:00:58 +02:00
Mark McKinstry
37907e4110 fix broken link for kairosdb image 2016-05-02 12:31:39 -04:00
Torkel Ödegaard
152e085310 fix(elasticsearch): minor form fix to elastic query editor 2016-05-02 16:34:07 +02:00
Torkel Ödegaard
372b394f5b Merge branch 'master' of github.com:grafana/grafana 2016-05-02 15:41:20 +02:00
Torkel Ödegaard
3889052c31 docs(): added whats new in v3 guide 2016-05-02 15:35:49 +02:00
Torkel Ödegaard
43182cb1eb updated 2016-05-02 14:49:50 +02:00
bergquist
de5a39f320 Revert "Revert "Merge branch 'utkarshcmu-rangeMaps'""
This reverts commit 58b91befde.
2016-05-02 13:17:57 +02:00
bergquist
58b91befde Revert "Merge branch 'utkarshcmu-rangeMaps'"
This reverts commit 8f976fd980, reversing
changes made to 072f51e300.
2016-05-02 13:15:18 +02:00
bergquist
8f976fd980 Merge branch 'utkarshcmu-rangeMaps' 2016-05-02 13:10:17 +02:00
bergquist
91047ffa30 tech(singlestat): convert to gf-form 2016-05-02 12:43:07 +02:00
bergquist
b42064acdb tech(singlestat): fixes indentation 2016-05-02 10:40:28 +02:00
bergquist
7e220b2b9e Merge branch 'rangeMaps' of https://github.com/utkarshcmu/grafana into utkarshcmu-rangeMaps 2016-05-02 10:26:30 +02:00
Torkel Ödegaard
072f51e300 fix(): updated changelog 2016-05-02 10:18:22 +02:00
Torkel Ödegaard
af95993d6d feat(): updated download links 2016-05-02 09:54:11 +02:00
Torkel Ödegaard
e6bccc5eff feat(influxdb): Added new functions moving_average and difference to query editor, closes #4698 2016-05-02 09:07:44 +02:00
yershalom
1b262d33f3 Added json to file name when exporting dashboard (#4869) 2016-05-01 15:31:01 +02:00
Jean-Baptiste Lespiau
c555bbce3d Add optional tooltip ordering 2016-05-01 01:32:36 +02:00
Utkarsh Bhatnagar
f6d538bb98 Bug fix, match tooltip timezone to X-axis timezone (#4855)
* Bug fix, match tooltip timezone to X-axis timezone

* Small improvement
2016-04-30 16:41:24 +02:00
joelanford
cbefd8f8ae Fixed legend labeling bug in Prometheus datasource (#4858) 2016-04-30 16:40:41 +02:00
Torkel Ödegaard
736ee3ffff fix(influxdb): Fixed issue with missing plus group by icon, fixes #4862 2016-04-30 16:35:42 +02:00
Torkel Ödegaard
36c583dddf fix(graphite): Fixed issue graphite png rendering option, fixes #4864 2016-04-30 16:26:25 +02:00
Torkel Ödegaard
70d03b7a1c fix(query editor): Fixed issue with removing query for data sources without collapsable query editors, fixes #4856 2016-04-29 23:20:48 +02:00
Torkel Ödegaard
0d85254a19 fix(annotations): Fixed issue with entering annotation edit view, fixes #4857 2016-04-29 23:14:39 +02:00
Torkel Ödegaard
e3376136ca fix(css): Fixed max dashboard title width (media query) for large screens, fixes #4859 2016-04-29 23:07:37 +02:00
Torkel Ödegaard
f8b4fcdc42 Merge branch 'master' into export-dashboard
Conflicts:
	packaging/publish/publish.sh
2016-04-29 15:01:47 +02:00
Torkel Ödegaard
6c340dcb65 docs(): updated download links 2016-04-29 11:24:43 +02:00
Torkel Ödegaard
6b467d5b3e fix(): spelling fix in templating editor 2016-04-29 08:40:53 +02:00
Archit Sharma
5372bcc7a2 fixes #4849 - minor fix for metric-segment-model (agg.field) 2016-04-29 07:21:52 +02:00
Torkel Ödegaard
0c9a19e38c Merge branch 'ds-template-var' 2016-04-28 19:31:56 +02:00
Torkel Ödegaard
8b4c7c94b8 feat(templating): completed work on templating as data source, closes #816 2016-04-28 19:31:43 +02:00
Torkel Ödegaard
c4440eab4c fix(dashboard): fixed issue with render event after resize 2016-04-28 19:15:54 +02:00
Torkel Ödegaard
7349427189 feat(data source variable): progress on data source as variable 2016-04-28 19:08:35 +02:00
Torkel Ödegaard
89ea25ca08 feat(templating): minor sort fix 2016-04-28 18:26:41 +02:00
Torkel Ödegaard
5d652dcaef fix(table): table column sorting fix 2016-04-28 15:48:49 +02:00
Torkel Ödegaard
d69788c9df Merge branch 'master' of github.com:grafana/grafana 2016-04-28 15:30:09 +02:00
Torkel Ödegaard
69c2fafa7a feat(elasticsearch): added geo hash bucket aggregation 2016-04-28 15:29:54 +02:00
Torkel Ödegaard
620e3a602d Merge pull request #4842 from grafana/pluginSettingFix
allow updates to secureJsonData.
2016-04-28 13:07:39 +02:00
woodsaj
ad8dbbb559 allow updates to secureJsonData.
SecureJsonData is stored as a json object in the DB. As the
secureJsonData is never returned to the user they are unable
to provide the full json object when performing updates instead
the user can only provide the specific keys they wish to update.
This commit ensures that only the provided keys are updated and
existing keys in the secureJsonData object are left untouched.
2016-04-28 18:39:23 +08:00
Torkel Ödegaard
5a241a8290 fix(): minor query editor fix 2016-04-28 10:29:36 +02:00
Torkel Ödegaard
4a332065d0 changelog(): updated changelog with notice about new query editors, closes #3900 2016-04-28 10:22:17 +02:00
Torkel Ödegaard
0e4b70a4a8 feat(query_editors): more work 2016-04-28 10:13:18 +02:00
Torkel Ödegaard
f1d4fd3e67 feat(query editors): changed chevron position 2016-04-27 21:24:41 +02:00
Torkel Ödegaard
7b560f9080 feat(query editors): converted OpenTSDB editor to new form styles 2016-04-27 16:29:59 +02:00
Torkel Ödegaard
0ebd921bbb feat(query editors): updated cloudwatch to new form styles 2016-04-27 11:07:26 +02:00
Torkel Ödegaard
206cb51219 feat(query editors): updated prometheus editor 2016-04-27 10:50:29 +02:00
Torkel Ödegaard
5e6485c210 feat(query editors): minor progress 2016-04-27 10:16:04 +02:00
Torkel Ödegaard
65b4945548 Merge branch 'master' into query-editor-style 2016-04-27 08:43:34 +02:00
Torkel Ödegaard
aa98ada141 fix(snapshots): fixed snapshot issue introdiuced yesterday 2016-04-26 14:51:06 +02:00
Torkel Ödegaard
26eeb6578d feat(gauge): polish to gauge, better handling of automatic font size, added option to hide threshold markers 2016-04-26 13:50:04 +02:00
Torkel Ödegaard
8bb07124f7 fix(gauge): validate min / max range, fixes #4820 2016-04-26 13:14:43 +02:00
Torkel Ödegaard
bce5c447b3 fix(apps): app dashboards can now be updated, fixes #4817 2016-04-26 12:52:44 +02:00
Torkel Ödegaard
34cb17546d fix(): minor fix for event emitter 2016-04-26 12:39:24 +02:00
utkarshcmu
c1cd1fedf4 Added relevant tests 2016-04-26 02:57:46 -07:00
utkarshcmu
5defc2a3d2 Fixed remove mapping function 2016-04-26 02:57:46 -07:00
utkarshcmu
7b2a21994f Moved mappings to new tab, added rangeMaps feature 2016-04-26 02:57:45 -07:00
Torkel Ödegaard
7c06604f16 Merge branch 'master' of github.com:grafana/grafana 2016-04-26 11:00:20 +02:00
Torkel Ödegaard
0762c38d35 fix(ds_edit): dont show warning when data source does not support testing, fixes #4811 2016-04-26 10:59:57 +02:00
bergquist
baac7809c5 docs(changelog): add notes about fixes for singlestat 2016-04-26 10:04:39 +02:00
bergquist
79ed99a940 fix(singlestat): fixes font size diffs for gauge 2016-04-26 10:00:13 +02:00
Torkel Ödegaard
bca0894f73 feat(query editors): progress on query editors 2016-04-26 09:58:55 +02:00
bergquist
9316bcf307 fix(singlestat): enables autoupdate on change
closes #4809
closes #4812
2016-04-26 09:51:31 +02:00
Torkel Ödegaard
60855643c4 Merge pull request #4807 from grafana/makefile
add basic Makefile, remove need for global grunt-cli
2016-04-25 19:01:44 +02:00
Dan Cech
650bb4c719 use npm test to run npm tests 2016-04-25 12:53:15 -04:00
Dan Cech
2244224b12 add basic Makefile, remove need for global grunt-cli 2016-04-25 12:44:26 -04:00
Torkel Ödegaard
bbf4d00319 fix(query editors): added select style to segment, used by data source selector 2016-04-25 15:49:33 +02:00
Torkel Ödegaard
6b813b4e2a feat(query editors): remember collapsed state 2016-04-25 15:11:40 +02:00
Torkel Ödegaard
529cb43397 Merge branch 'master' of github.com:grafana/grafana into query-editor-style 2016-04-25 14:30:41 +02:00
Torkel Ödegaard
6bc898b215 fix(influxdb): fixed issue with using multi value template vars in influxdb measurement clause, fixes #4797 2016-04-25 14:29:51 +02:00
Torkel Ödegaard
1a433de0b4 Merge branch 'master' into query-editor-style 2016-04-25 14:22:36 +02:00
Torkel Ödegaard
4d802df040 fix(influxdb): fixed issue with using multi value template vars in influxdb measurement clause, fixes #4797 2016-04-25 14:22:15 +02:00
Torkel Ödegaard
04a79175bf fix(plugins): only add app nav link if it has any pages/dashboards with role matching current user, fixes #4784 2016-04-25 14:00:49 +02:00
Torkel Ödegaard
97656d65ec db(dashboard): minor fix for dashboard delete 2016-04-25 11:22:13 +02:00
Torkel Ödegaard
ba28d2e13f Merge branch 'master' of github.com:grafana/grafana 2016-04-25 09:26:57 +02:00
Torkel Ödegaard
711992c8e2 fix(influxdb): minor fix for duplicated db param to proxied influxdb call, fixes #4703 2016-04-25 09:26:47 +02:00
Carl Bergquist
31624b410a Merge pull request #4800 from 1tylermitchell/patch-1
typo
2016-04-25 08:01:39 +02:00
Torkel Ödegaard
00827ce921 fix(): let binding cycle complete before adding panel to dom 2016-04-24 12:50:33 +02:00
Tyler Mitchell
21d2a51cd3 typo
tabs != tags
2016-04-23 22:00:42 -07:00
bergquist
c0384a04f8 Merge branch 'cli_upgradeFix' 2016-04-23 14:40:05 +02:00
bergquist
ee0c4cd194 docs(changelog): add note about cli issue
closes #4651
2016-04-23 14:39:42 +02:00
bergquist
07b13e24fa style(cli): add some color to error messages 2016-04-23 14:39:42 +02:00
bergquist
0855f51436 feat(cli): improves defer error handling 2016-04-23 14:39:42 +02:00
bergquist
70acfb2cfd fix(cli): adds better help text.
The zip lib is throwing panics sometimes when the response is malformed.
The cli will now try to download the zip file up to three times before
aborting. The cli gives a better error message and informes the user
about retrying.

closes #4651
2016-04-23 14:39:42 +02:00
Torkel Ödegaard
29a2b2032a Merge pull request #4794 from grafana/issue-4767
Updated link color in text panel to be -link-color
2016-04-22 18:37:03 +02:00
Torkel Ödegaard
af2efbe480 Merge pull request #4796 from grafana/g-net-links
fix broken link to grafana.net, standardize on https://grafana.net for links
2016-04-22 18:36:42 +02:00
Dan Cech
25b0773a94 fix broken link to grafana.net, standardize on https://grafana.net for links 2016-04-22 12:13:39 -04:00
Matt Toback
349f6b51a5 Updated link color in text panel to be -link-color 2016-04-22 11:32:19 -04:00
Torkel Ödegaard
9917de09af fix(graph): removed angular copy that was no longer needed 2016-04-22 15:49:51 +02:00
Torkel Ödegaard
884eef32c9 Merge pull request #4793 from daniellee/panel_defaults
fix(panels): avoid deep copy problem for panel defaults
2016-04-22 15:47:59 +02:00
Daniel Lee
16dbf3166d fix(panels): avoid deep copy problem for panel defaults
Moves the defaults to be an instance property. This solves
the problem of lodash defaults function not doing a deep
copy. The symptom of this is that new deep properties for
a panel are assigned to every panel of the same type by
the defaults function in the constructor.
2016-04-22 15:29:33 +02:00
Carl Bergquist
be19f8888e Merge pull request #4792 from grafana/revert-4790-revert-3688-gauges
Revert "Revert "Gauges""
2016-04-22 15:06:13 +02:00
Torkel Ödegaard
3bbc86bcf2 Merge pull request #4719 from nlf/master
dont quote numbers for influxdb, closes #4163
2016-04-22 15:04:14 +02:00
Torkel Ödegaard
8b656f15b9 feat(graphite): added stddevSeries func def, closes #4782 2016-04-22 14:57:16 +02:00
Carl Bergquist
453f8b312a Revert "Revert "Gauges"" 2016-04-22 14:55:35 +02:00
Torkel Ödegaard
723bfa70db fix(table panel): fixed issue with string array formating, fixes #4791 2016-04-22 14:46:32 +02:00
Torkel Ödegaard
45dd9c5795 fix(graph panel): fix for graph panel alignment when legend is in table mode, fixes #4772 2016-04-22 14:36:20 +02:00
Torkel Ödegaard
fa479afdaa Merge branch 'master' of github.com:grafana/grafana 2016-04-22 14:00:08 +02:00
Torkel Ödegaard
1dfeb192a3 fix(templating): another fix for templating and custom all value escaping, fixes #4787 2016-04-22 13:59:54 +02:00
Carl Bergquist
1f9c2add7c Merge pull request #4790 from grafana/revert-3688-gauges
Revert "Gauges"
2016-04-22 13:05:54 +02:00
Carl Bergquist
24fbcd8dea Revert "Gauges" 2016-04-22 13:05:43 +02:00
bergquist
db15bf23b8 fix(sass): fixes sass lint issue 2016-04-22 12:09:02 +02:00
bergquist
de52ca4785 docs(changelog): adds gauges to changelog 2016-04-22 11:54:09 +02:00
Carl Bergquist
2748a3fbd8 Merge pull request #3688 from keis/gauges
Gauges
2016-04-22 11:49:35 +02:00
Torkel Ödegaard
dfe36fb702 feat(panel): added new panel event panel-initialized 2016-04-22 11:41:56 +02:00
Torkel Ödegaard
297c829bdc tech(): updatad sass-lint 2016-04-22 09:47:30 +02:00
Torkel Ödegaard
bd933badb1 Merge pull request #4779 from bergquist/fix_snapshots
Fix broken snapshots in grafana 2.6
2016-04-22 09:35:02 +02:00
bergquist
0fb4141ce4 docs(changelog): add note about scrollbar fix #4769 2016-04-21 10:23:09 +02:00
bergquist
51de894692 fix(snapshots): sets default value for snapshot name
make it possible for < 3.0 instances to publish snapshots

ref #4778
2016-04-21 09:59:48 +02:00
Torkel Ödegaard
7079b5d770 fix(dashboard list): fixed minor issue with dashboard list panel, fixes #4768 2016-04-20 09:15:45 -07:00
Torkel Ödegaard
41e5812a22 Merge pull request #4771 from mtanda/cloudwatch_kinesis_metrics
(cloudwatch) add kinesis metrics
2016-04-20 08:57:26 -07:00
Torkel Ödegaard
8d5f28b33a Merge pull request #4774 from ycombinator/update-es-logo
Updating Elasticsearch logo
2016-04-20 08:56:21 -07:00
Shaunak Kashyap
3925bcb94c Updating Elasticsearch logo 2016-04-20 08:50:28 -07:00
Mitsuhiro Tanda
8d1ac8c7f5 (cloudwatch) add kinesis metrics 2016-04-20 14:33:08 +09:00
Carl Bergquist
9f4ad73698 Merge pull request #4758 from bergquist/cli_local_pluginfolder
CLI: Adds support for local plugin folder
2016-04-19 17:30:01 +02:00
bergquist
0108b5eb88 fix(singlestat): adds support for lighttheme 2016-04-19 16:18:29 +02:00
bergquist
0c6841bdc7 fix(singlestat): adds support for fontsizes in gagues 2016-04-19 16:18:22 +02:00
David Keijser
c455e501ac Add gauge option to singlestat 2016-04-19 16:18:09 +02:00
David Keijser
44c1d8c1e5 Add jquery.flot.gauge 2016-04-19 16:18:09 +02:00
bergquist
ff22f43002 fix(cli): fixes missplaced % 2016-04-19 14:46:03 +02:00
bergquist
4e8396dbce fix(graph): sets legend table scroll to auto
closes #4760
2016-04-19 13:41:35 +02:00
bergquist
d38d4efc18 style(cli): improve logging to find install crash 2016-04-19 10:39:55 +02:00
bergquist
a8c68e33db feat(cli): add more logging for failed install 2016-04-19 10:22:02 +02:00
bergquist
903d1b7797 tech(cli): dont use defer statements in loops 2016-04-19 09:13:58 +02:00
bergquist
5abaf26b5f style(cli): remove some logging 2016-04-19 08:39:22 +02:00
bergquist
485a377800 fix(cli): adds support for local plugin folder
closes #4572
2016-04-19 08:27:26 +02:00
Torkel Ödegaard
bd21a08bc9 fix(templating): fixed encoding of all value for regex, and custom all value, fixes #4755, fixes #4736 2016-04-18 17:33:51 -04:00
Torkel Ödegaard
99ae38a232 Merge pull request #4750 from bergquist/fix_influxb_showtag_values
[Influxb] Support for multible measurement results in showtag values
2016-04-18 13:22:07 -04:00
bergquist
c148e54bbd style(influxdb): improve naming 2016-04-18 18:52:09 +02:00
bergquist
267ab822c2 tech(influxdb): uses hashmap for uniqueness 2016-04-18 18:46:50 +02:00
Torkel Ödegaard
39cdaf5175 ux(query-editors): more progress and fixes 2016-04-18 11:35:24 -04:00
bergquist
80818f80a9 tech(grunt): add check for not including "only" in tests 2016-04-18 17:12:53 +02:00
bergquist
fde6eee4f4 fix(influxdb): adds support for multi table values
When quering for tag values without measurement
all tags and values should be shown

closes #4726
2016-04-18 16:27:06 +02:00
Torkel Ödegaard
14ec69a160 Merge remote-tracking branch 'origin/master' into query-editor-style 2016-04-18 09:51:35 -04:00
Torkel Ödegaard
8ebe9d1e16 Merge branch 'query-editor-style' of github.com:grafana/grafana into query-editor-style 2016-04-18 09:51:28 -04:00
bergquist
7e66d0bcc1 fix(): remove only usage in tests 2016-04-18 15:25:06 +02:00
Torkel Ödegaard
4515e66783 feat(query editors): more progress on ES query editor 2016-04-18 08:43:11 -04:00
Torkel Ödegaard
1069f485da ux(query_editors): handle text overflow in collapsed mode 2016-04-17 22:24:40 -04:00
Torkel Ödegaard
4c4835e869 ux(query-editors): more progress on elastic query editor 2016-04-17 22:04:43 -04:00
Torkel Ödegaard
a1faaa133c feat(): query editors, started work on updated ES query editor 2016-04-17 17:17:30 -04:00
Torkel Ödegaard
805fd18b7b feat(query editors): more work on query editors make over 2016-04-17 16:43:13 -04:00
Torkel Ödegaard
33f7b8479e ux(query editors): progress on new query editor styles 2016-04-17 12:14:25 -04:00
Torkel Ödegaard
68bd82f1b6 Merge branch 'master' into query-editor-style 2016-04-16 13:46:05 -04:00
Torkel Ödegaard
13471ae2c4 feat(templating): templated ds progress 2016-04-16 13:43:16 -04:00
Torkel Ödegaard
822bf13b7a Merge pull request #4728 from grafana/code-style-improvements
Code style improvements
2016-04-16 12:09:40 -04:00
Torkel Ödegaard
1cce5fdfe1 feat(templating): polished variable template edit forms, added new template variable type: datasource 2016-04-16 12:03:29 -04:00
Torkel Ödegaard
6b2fedb1c2 Merge branch 'master' of github.com:grafana/grafana 2016-04-15 19:57:12 -04:00
Torkel Ödegaard
e307ada374 ux(): tooltip improvement 2016-04-15 19:56:39 -04:00
Torkel Ödegaard
4f2628c221 fix(): fixed issue with templating preview, fixes #4714 2016-04-15 18:50:48 -04:00
Torkel Ödegaard
0f16066915 fix(): zoom out tooltip fix, fixes #4729 2016-04-15 18:32:03 -04:00
Matt Toback
151d8db98d removed unnecessary style 2016-04-15 15:00:29 -04:00
Matt Toback
614b26fff6 Fixed inline code styles and increase line heights in lists to accommodate code 2016-04-15 14:58:20 -04:00
Torkel Ödegaard
49b2743a37 Merge branch 'master' of github.com:grafana/grafana 2016-04-15 14:36:51 -04:00
Torkel Ödegaard
8e37de19c9 ux(): minor fix to tooltip in template editor view 2016-04-15 14:36:43 -04:00
Matt Toback
38bda92bdc Update dashnav.html 2016-04-15 13:26:27 -04:00
Torkel Ödegaard
83ba6638a1 bumped version 2016-04-15 10:50:21 -04:00
Torkel Ödegaard
4832ecf3e7 docs(): updated download links 2016-04-15 09:25:09 -04:00
Torkel Ödegaard
2e8ed97355 changelog(grafana-cli): fixed issue with grafana-cli and plugins dir, fixes #4723 2016-04-15 09:13:06 -04:00
Torkel Ödegaard
d98839fc19 Revert "feat(cli): detects plugin folder for dev env"
This reverts commit a5eda6a87b.
2016-04-15 09:01:27 -04:00
Torkel Ödegaard
0f71838fdf feat(dash export): dashboard export can now replace datasource names with variable and add inputs section 2016-04-14 21:13:01 -04:00
Nathan LaFreniere
b6de656cf1 dont quote numbers for influxdb, closes #4163 2016-04-14 17:08:54 -07:00
Torkel Ödegaard
75555c470b Update latest.json 2016-04-14 18:09:04 -04:00
Torkel Ödegaard
4d0b14fbb4 feat(exporter): stared work on dashboard exporter that cleans up repeated panels etc 2016-04-14 17:31:34 -04:00
Torkel Ödegaard
1f9922a5aa refactor(): moved dashboard_srv and DashboardCtrl to typescript 2016-04-14 16:53:19 -04:00
Torkel Ödegaard
b3f3b70b90 Merge branch 'master' of github.com:grafana/grafana 2016-04-14 14:15:59 -04:00
Torkel Ödegaard
924800b7df bumped version 2016-04-14 14:15:47 -04:00
Matt Toback
d27da57b02 Fixed the fix. 2016-04-14 12:39:37 -04:00
Torkel Ödegaard
f1a01aed7e Merge pull request #4711 from grafana/issue-4704
Updated colors to fix issue
2016-04-14 12:30:47 -04:00
Matt Toback
c1a5771fcd Updated colors to fix issue 2016-04-14 11:38:07 -04:00
Matt Toback
8ac5c36735 Still not fixed, not sure why.
despite having pushed that code with @torkelo.
2016-04-14 11:12:00 -04:00
Torkel Ödegaard
6355896584 fix(snapshots): Fixed issue with empty snapshots, fixes #4706 2016-04-14 11:06:48 -04:00
Torkel Ödegaard
6216ce455f fix(pluginlist): fixed issue with pluginlist link, fixes #4705 2016-04-14 10:55:24 -04:00
Torkel Ödegaard
c0832995ae Merge branch 'master' of github.com:grafana/grafana 2016-04-14 08:47:38 -04:00
Torkel Ödegaard
9469b20cbd fix(graph): Fixed issue with light theme text color issue in tooltip, fixes #4702 2016-04-14 08:41:54 -04:00
Torkel Ödegaard
573457c03f fix(build): fixed build script issue 2016-04-13 17:48:20 -04:00
Torkel Ödegaard
5c395424c6 updated changelog 2016-04-13 17:42:33 -04:00
Torkel Ödegaard
f6d53df282 Merge branch 'master' of github.com:grafana/grafana 2016-04-13 17:33:17 -04:00
Torkel Ödegaard
e4374b1d56 docs(): updated download links 2016-04-13 17:33:03 -04:00
Torkel Ödegaard
7302ddaba5 docs(): fixed docs fixes #46688 2016-04-13 16:43:00 -04:00
Torkel Ödegaard
7456514816 fix(templating): fixed issue with template variables that use regex extraction, fixes #4672 2016-04-13 16:41:19 -04:00
Torkel Ödegaard
d9ad4cf2fc fix(): made plugin settings api call accessable for viewer roles 2016-04-13 13:03:41 -04:00
Torkel Ödegaard
8b4efbed06 Merge branch 'master' of github.com:grafana/grafana 2016-04-13 12:23:45 -04:00
Torkel Ödegaard
10131aa8a0 fix(pluginlist): fixed issue with home dashboard and new pluginlist panel that casued permission denied error for non admin users, fixes #4686 2016-04-13 12:23:29 -04:00
Torkel Ödegaard
23dc85c1de Merge pull request #4628 from timstanley1985/master
Fix build on RPi.  Building from source timesout on karma tests so increase timeouts
2016-04-13 10:32:46 -04:00
Torkel Ödegaard
338c6b5a5c Merge pull request #4671 from grafana/login-page-style
Updated background color on div
2016-04-13 10:28:40 -04:00
Matt Toback
c13ebce2f6 Update module.html 2016-04-12 17:01:30 -04:00
Matt Toback
b6ccd7ffbe Updated background color on div 2016-04-12 15:18:47 -04:00
Torkel Ödegaard
ad0794cc59 ux(): updated light theme 2016-04-12 14:26:55 -04:00
Torkel Ödegaard
6961cb7440 ux(): reduced tooltip border radius 2016-04-12 13:29:31 -04:00
Torkel Ödegaard
9868edb138 ux(): changed tooltip style 2016-04-12 13:00:33 -04:00
Torkel Ödegaard
e822fad505 fix(timepicker): fixed issues and added some polish to timepicker shift back/forward buttons 2016-04-12 12:41:17 -04:00
Torkel Ödegaard
3ab5427019 fix(timepicker): fixed issues and added some polish to timepicker shift back/forward buttons 2016-04-12 12:39:59 -04:00
Torkel Ödegaard
7afb6fa3e3 ux(ds edit): combine save and test connection buttons, closes #4658 2016-04-12 11:20:03 -04:00
Torkel Ödegaard
29dff7ba1a fix(graph): fixed color picker appearingunder pinned side nav, fixes #4556 2016-04-12 11:07:34 -04:00
Torkel Ödegaard
329ee8d9f1 fix(prometheus): added template variable escape format to prometheus annotations queries, fixes #4656 2016-04-12 10:50:58 -04:00
Torkel Ödegaard
f70e0003f8 Merge branch 'master' of github.com:grafana/grafana 2016-04-12 10:29:07 -04:00
Torkel Ödegaard
bb0eb29c82 Update latest.json 2016-04-12 10:28:56 -04:00
Torkel Ödegaard
47bba71d7f fixed update check 2016-04-12 10:28:32 -04:00
bergquist
6b8921c8c5 Merge branch 'utkarshcmu-move' 2016-04-12 16:22:27 +02:00
bergquist
7d09579e3f feat(timepicker): adds arrows to move back and forth in current dashboard
closes #119
2016-04-12 16:21:29 +02:00
bergquist
e5c9a24c33 Merge branch 'master' into utkarshcmu-move 2016-04-12 16:21:20 +02:00
Torkel Ödegaard
e7626befc5 updated version 2016-04-12 10:17:39 -04:00
Torkel Ödegaard
905d31442c fix(annotations): make sure a data source that supports annotations is used in annotation editor when creating new 2016-04-12 10:16:40 -04:00
bergquist
963001ba1a Merge branch 'move' of https://github.com/utkarshcmu/grafana into utkarshcmu-move 2016-04-12 15:22:38 +02:00
Torkel Ödegaard
75649c49d5 Merge branch 'master' into wizard 2016-04-11 18:18:09 -04:00
timstanley1985
92f5f8dced Fix build on RPi. Building from source timesout on karma tests so increase timeouts 2016-04-09 17:09:55 +01:00
utkarshcmu
6a55ec6955 Changed time shift icons 2016-04-07 02:21:54 -07:00
utkarshcmu
e470786fb9 Backward and forward arrows for time shift 2016-04-07 01:30:49 -07:00
Torkel Ödegaard
6bb001e416 Merge branch 'master' into query-editor-style 2016-04-04 13:55:55 -04:00
Torkel Ödegaard
50d773988b ux(): updated graphite editor 2016-03-29 19:17:32 +02:00
Torkel Ödegaard
d2239427f2 ux(): big progress on updating query editors 2016-03-29 19:03:24 +02:00
Torkel Ödegaard
24a7d4f816 ux(): query editors, added group by 2016-03-29 17:56:34 +02:00
Torkel Ödegaard
a4f9621473 Merge branch 'master' into query-editor-style 2016-03-29 17:45:24 +02:00
Torkel Ödegaard
437b880b3e feat(plugins): work on setup wizard started 2016-03-25 22:14:29 +01:00
Torkel Ödegaard
bd6a68bfe5 ux(): more changes to influxdb query editor 2016-03-20 18:01:25 +01:00
Torkel Ödegaard
a5a244767a Merge branch 'master' into query-editor-style 2016-03-20 17:39:31 +01:00
Torkel Ödegaard
55189200a4 ux(): updated query editor test 2016-03-20 16:18:31 +01:00
553 changed files with 77801 additions and 35388 deletions

3
.floo Normal file
View File

@@ -0,0 +1,3 @@
{
"url": "https://floobits.com/raintank/grafana"
}

12
.flooignore Normal file
View File

@@ -0,0 +1,12 @@
#*
*.o
*.pyc
*.pyo
*~
extern/
node_modules/
tmp/
data/
vendor/
public_gen/
dist/

View File

@@ -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?

View File

@@ -10,4 +10,4 @@
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"validateIndentation": 2
}
}

View File

@@ -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
View File

@@ -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",

File diff suppressed because it is too large Load Diff

View 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
}
}
}

View 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"))
}

View 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)
}

View 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
}

View 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)

View 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

View 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.

View File

@@ -0,0 +1,38 @@
[![GoDoc](https://godoc.org/github.com/go-stack/stack?status.svg)](https://godoc.org/github.com/go-stack/stack)
[![Go Report Card](https://goreportcard.com/badge/go-stack/stack)](https://goreportcard.com/report/go-stack/stack)
[![TravisCI](https://travis-ci.org/go-stack/stack.svg?branch=master)](https://travis-ci.org/go-stack/stack)
[![Coverage Status](https://coveralls.io/repos/github/go-stack/stack/badge.svg?branch=master)](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.

View 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
}

View File

@@ -0,0 +1,10 @@
language: go
go:
- 1.1
- 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- tip

View 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

View 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.

View File

@@ -0,0 +1,70 @@
![obligatory xkcd](http://imgs.xkcd.com/comics/standards.png)
# log15 [![godoc reference](https://godoc.org/github.com/inconshreveable/log15?status.png)](https://godoc.org/github.com/inconshreveable/log15) [![Build Status](https://travis-ci.org/inconshreveable/log15.svg?branch=master)](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

View 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

View 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])
}

View 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))
}

View 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))
}

View 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)
}

View 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
}

View 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)
}

View 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))
}

View 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.

View 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
}

View 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

View 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
}

View 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

View 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
}

View File

@@ -0,0 +1,7 @@
package term
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
type Termios syscall.Termios

View 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
}

View 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.

View 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)

View File

@@ -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"

View File

@@ -1,8 +1,9 @@
go-sqlite3
==========
[![Build Status](https://travis-ci.org/mattn/go-sqlite3.png?branch=master)](https://travis-ci.org/mattn/go-sqlite3)
[![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.png?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
[![Build Status](https://travis-ci.org/mattn/go-sqlite3.svg?branch=master)](https://travis-ci.org/mattn/go-sqlite3)
[![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.svg?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
[![GoDoc](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](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
------

View File

@@ -6,7 +6,11 @@
package sqlite3
/*
#ifndef USE_LIBSQLITE3
#include <sqlite3-binding.h>
#else
#include <sqlite3.h>
#endif
#include <stdlib.h>
*/
import "C"

View 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
}
}

View File

@@ -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

View File

@@ -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)
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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")
}
}

View 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"

View 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"

View 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"

View 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"

View 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
}

View 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")
}

View File

@@ -9,6 +9,5 @@ package sqlite3
/*
#cgo CFLAGS: -I.
#cgo linux LDFLAGS: -ldl
#cgo LDFLAGS: -lpthread
*/
import "C"

View File

@@ -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")
}
}

View File

@@ -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)
}

View File

@@ -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"

View File

@@ -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
View 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

View File

@@ -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)

View File

@@ -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%

View File

@@ -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",

View File

@@ -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() {

View File

@@ -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}

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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>

View File

@@ -0,0 +1 @@
hostfs /.dockerinit ext4 ro,relatime,user_xattr,barrier=1,data=ordered 0 0

View 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

View File

@@ -0,0 +1,5 @@
#!/bin/bash
envtpl /etc/collectd/collectd.conf.tpl
collectd -f

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
memcached:
image: memcached:latest
ports:
- "11211:11211"

View File

@@ -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

View File

@@ -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

View File

@@ -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']

View File

@@ -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']
```

View File

@@ -1 +1 @@
3.0.0
3.1.0

View File

@@ -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']

View File

@@ -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.

View File

@@ -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.
![](/img/v2/kairos_query_editor.png)
![](/img/v2/kairos_query_editor.jpg)
For details on KairosDB metric queries checkout the official.
- [Query Metrics - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/QueryMetrics.html).

View File

@@ -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.
![](/img/v2/add_OpenTSDB.jpg)
![](/img/v2/add_OpenTSDB.png)
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)

View 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.

View 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.
Weve 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.
Itll 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. Youll 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. Itll 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. Youll 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
Weve always tried to focus on a good looking, usable, and responsive
UI. Weve 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.
Heres 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.

View 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**:

View File

@@ -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/*`

View File

@@ -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/)

View 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"}

View File

@@ -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
---

View File

@@ -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.`

View File

@@ -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

View File

@@ -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
```

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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
![](/img/v3/annotations_prom.png)
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))

View File

@@ -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