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 https://github.com/grafana/grafana/commit/2034d4b9710b0cb9fd0cdf14aa9981cd0417eda4
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
View File
@@ -0,0 +1,3 @@
{
"url": "https://floobits.com/raintank/grafana"
}
+12
View File
@@ -0,0 +1,12 @@
#*
*.o
*.pyc
*.pyo
*~
extern/
node_modules/
tmp/
data/
vendor/
public_gen/
dist/
+14 -9
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?
+1 -1
View File
@@ -10,4 +10,4 @@
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"validateIndentation": 2
}
}
+113 -1
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)
+22 -1
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
@@ -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
}
}
}
@@ -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"))
}
@@ -0,0 +1,149 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package sts_test
import (
"bytes"
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
)
var _ time.Duration
var _ bytes.Buffer
func ExampleSTS_AssumeRole() {
svc := sts.New(session.New())
params := &sts.AssumeRoleInput{
RoleArn: aws.String("arnType"), // Required
RoleSessionName: aws.String("roleSessionNameType"), // Required
DurationSeconds: aws.Int64(1),
ExternalId: aws.String("externalIdType"),
Policy: aws.String("sessionPolicyDocumentType"),
SerialNumber: aws.String("serialNumberType"),
TokenCode: aws.String("tokenCodeType"),
}
resp, err := svc.AssumeRole(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
func ExampleSTS_AssumeRoleWithSAML() {
svc := sts.New(session.New())
params := &sts.AssumeRoleWithSAMLInput{
PrincipalArn: aws.String("arnType"), // Required
RoleArn: aws.String("arnType"), // Required
SAMLAssertion: aws.String("SAMLAssertionType"), // Required
DurationSeconds: aws.Int64(1),
Policy: aws.String("sessionPolicyDocumentType"),
}
resp, err := svc.AssumeRoleWithSAML(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
func ExampleSTS_AssumeRoleWithWebIdentity() {
svc := sts.New(session.New())
params := &sts.AssumeRoleWithWebIdentityInput{
RoleArn: aws.String("arnType"), // Required
RoleSessionName: aws.String("roleSessionNameType"), // Required
WebIdentityToken: aws.String("clientTokenType"), // Required
DurationSeconds: aws.Int64(1),
Policy: aws.String("sessionPolicyDocumentType"),
ProviderId: aws.String("urlType"),
}
resp, err := svc.AssumeRoleWithWebIdentity(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
func ExampleSTS_DecodeAuthorizationMessage() {
svc := sts.New(session.New())
params := &sts.DecodeAuthorizationMessageInput{
EncodedMessage: aws.String("encodedMessageType"), // Required
}
resp, err := svc.DecodeAuthorizationMessage(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
func ExampleSTS_GetFederationToken() {
svc := sts.New(session.New())
params := &sts.GetFederationTokenInput{
Name: aws.String("userNameType"), // Required
DurationSeconds: aws.Int64(1),
Policy: aws.String("sessionPolicyDocumentType"),
}
resp, err := svc.GetFederationToken(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
func ExampleSTS_GetSessionToken() {
svc := sts.New(session.New())
params := &sts.GetSessionTokenInput{
DurationSeconds: aws.Int64(1),
SerialNumber: aws.String("serialNumberType"),
TokenCode: aws.String("tokenCodeType"),
}
resp, err := svc.GetSessionToken(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
+130
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
}
@@ -0,0 +1,38 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Package stsiface provides an interface for the AWS Security Token Service.
package stsiface
import (
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/sts"
)
// STSAPI is the interface type for sts.STS.
type STSAPI interface {
AssumeRoleRequest(*sts.AssumeRoleInput) (*request.Request, *sts.AssumeRoleOutput)
AssumeRole(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
AssumeRoleWithSAMLRequest(*sts.AssumeRoleWithSAMLInput) (*request.Request, *sts.AssumeRoleWithSAMLOutput)
AssumeRoleWithSAML(*sts.AssumeRoleWithSAMLInput) (*sts.AssumeRoleWithSAMLOutput, error)
AssumeRoleWithWebIdentityRequest(*sts.AssumeRoleWithWebIdentityInput) (*request.Request, *sts.AssumeRoleWithWebIdentityOutput)
AssumeRoleWithWebIdentity(*sts.AssumeRoleWithWebIdentityInput) (*sts.AssumeRoleWithWebIdentityOutput, error)
DecodeAuthorizationMessageRequest(*sts.DecodeAuthorizationMessageInput) (*request.Request, *sts.DecodeAuthorizationMessageOutput)
DecodeAuthorizationMessage(*sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error)
GetFederationTokenRequest(*sts.GetFederationTokenInput) (*request.Request, *sts.GetFederationTokenOutput)
GetFederationToken(*sts.GetFederationTokenInput) (*sts.GetFederationTokenOutput, error)
GetSessionTokenRequest(*sts.GetSessionTokenInput) (*request.Request, *sts.GetSessionTokenOutput)
GetSessionToken(*sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error)
}
var _ STSAPI = (*sts.STS)(nil)
+16
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
+13
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.
+38
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.
+349
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
}
+10
View File
@@ -0,0 +1,10 @@
language: go
go:
- 1.1
- 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- tip
+11
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
+13
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.
+70
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
+333
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
+257
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])
}
+356
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))
}
+26
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))
}
+23
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)
}
+208
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
}
+67
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)
}
+55
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))
}
+21
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.
@@ -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
}
@@ -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
@@ -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
}
@@ -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
@@ -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
}
@@ -0,0 +1,7 @@
package term
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
type Termios syscall.Termios
@@ -0,0 +1,26 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package term
import (
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTty returns true if the given file descriptor is a terminal.
func IsTty(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
+20
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.
@@ -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)
+6 -2
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"
+23 -4
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
------
+4
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"
+336
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
}
}
+29 -12
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
-242
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
+409 -56
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
-83
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")
}
}
+13
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"
+13
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"
+12
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"
@@ -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"
@@ -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
}
@@ -0,0 +1,23 @@
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// +build sqlite_omit_load_extension
package sqlite3
/*
#cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION
*/
import "C"
import (
"errors"
)
func (c *SQLiteConn) loadExtensions(extensions []string) error {
return errors.New("Extensions have been disabled for static builds")
}
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
return errors.New("Extensions have been disabled for static builds")
}
-1
View File
@@ -9,6 +9,5 @@ package sqlite3
/*
#cgo CFLAGS: -I.
#cgo linux LDFLAGS: -ldl
#cgo LDFLAGS: -lpthread
*/
import "C"
-947
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")
}
}
+7 -10
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)
}
+1 -1
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"
+60 -5
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
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
+23 -6
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)
+1 -1
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%
+1 -1
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",
+4 -6
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() {
+3 -3
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}
+39 -12
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
+53 -10
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
+16
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
+37
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
+106
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>
+1
View File
@@ -0,0 +1 @@
hostfs /.dockerinit ext4 ro,relatime,user_xattr,barrier=1,data=ordered 0 0
+12
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
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
envtpl /etc/collectd/collectd.conf.tpl
collectd -f
+7
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
+9 -1
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
+5
View File
@@ -0,0 +1,5 @@
memcached:
image: memcached:latest
ports:
- "11211:11211"
+7 -1
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
+16
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
+1 -1
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']
+48 -5
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']
```
+1 -1
View File
@@ -1 +1 @@
3.0.0
3.1.0
+3 -1
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']
+4 -2
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.
+1 -1
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).
+10 -3
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)
+68
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.
+223
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.
+1 -1
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**:
-29
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/*`
+1
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/)
+100
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"}
+1 -1
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
---
+40 -2
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.`
+3 -10
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
+28 -3
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
```
+5 -24
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
+1 -1
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
+1 -1
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)
+7
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))
-2
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