From cea462f03b593f9064473ad182a70776214be933 Mon Sep 17 00:00:00 2001 From: Uday Date: Tue, 30 Jul 2019 17:29:05 +0200 Subject: [PATCH] latest master (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make sure the default for EnforceMetricName is ✅ (#518) Signed-off-by: Goutham Veeramachaneni * Enable tracing loki in helm chart (#496) * Enable tracing loki in helm chart Tracing support from #328, need to support config in helm chart Signed-off-by: Xiang Dai <764524258@qq.com> * Use camel case for variables Signed-off-by: Xiang Dai <764524258@qq.com> * update condition Signed-off-by: Xiang Dai <764524258@qq.com> * Update troubleshooting (#498) * Update troubleshooting - remove "no label" title - add tracing part Signed-off-by: Xiang Dai <764524258@qq.com> * Add helm help Signed-off-by: Xiang Dai <764524258@qq.com> * Take 2 for fix the limit settings (#519) * Revert "Make sure the default for EnforceMetricName is ✅ (#518)" This reverts commit 199746a130bdc5d21e50612ef49b60e37251548f. * Fix overrides unmarshalling properly Signed-off-by: Goutham Veeramachaneni * Add target config (#486) * Add target config Support costomize target config. Signed-off-by: Xiang Dai <764524258@qq.com> * Update default value Signed-off-by: Xiang Dai <764524258@qq.com> * bump helm version Signed-off-by: Xiang Dai <764524258@qq.com> * fix a typo Signed-off-by: Xiang Dai <764524258@qq.com> * bump up chart version Signed-off-by: Xiang Dai <764524258@qq.com> * support config chunk size (#464) * support config chunk size Signed-off-by: Xiang Dai <764524258@qq.com> * fix lint Signed-off-by: Xiang Dai <764524258@qq.com> * review feedback * Add option (#528) * Add chunk_block_size option Introduce by #464. Signed-off-by: Xiang Dai <764524258@qq.com> * fix white noise Signed-off-by: Xiang Dai <764524258@qq.com> * Bump up helm version Signed-off-by: Xiang Dai <764524258@qq.com> * Fix typo in example config (#530) * Fix #531 chunk_block_size not found Signed-off-by: Steven Sheehy * don't delete elements from a map while iterating over it improve locking of positions * need to remove this return statement or positions will never be cleaned up * Adding `make debug` support to build debug binaries and debug containers which wrap the binary with delve and allow for remote debugging * using the timestamp from the log file might lead to undesired behavior as it could be way in the past or future depending on the clock for the source system generating the logs. Given that it's compared to the servers time.Now() when looking for idle chunks it's probably best to use the server time when setting the value. (#546) * Better buckets for chunk sizes (#529) Signed-off-by: Goutham Veeramachaneni * switch to golangci-lint linter (#539) * switch to golangci-lint linter * fixes for review comments * Promtail targets and service discovery pages (#532) * add a custom server for loki with assets embedded * adds a targets page for promtail to see discovered files and labels * lint fixes * fix css table size * add service discovery logic * add service discovery template * add promtail pages documentation * ignored gen file in linter * improves memory usage of golangci-linter * Send logs to multiple loki instances (#536) * Adds the ability to provide multiple Loki URL For backward compatibility `client:` still works with flag. * add some tests for multi client * update ksonnet module to support multiple client * fix comment * fix lint issues * fix backward compatibility with client config (#554) * fix backward compatibility with client config * fix comment * Add scrape config for control plane static pods Signed-off-by: Steven Sheehy * make clean removes `pkg/promtail/server/ui/assets_vfsdata.go` which meant the `pkg/promtail/server/ui/assets_vfsdata.go: assets` target is never activated causing a build error, updating to make the target hit on `server.go` which has a dependency on the deleted `assets_vfsdata.go` triggering a run of `make assets` before go builds that file (#555) * Support CRI 1.14+ directory change Signed-off-by: Steven Sheehy * Parse pipelines of regex matches. Signed-off-by: Tom Wilkie * Errors and wiring. Signed-off-by: Tom Wilkie * Wire up LogQL filters in the ingester. Signed-off-by: Tom Wilkie * Remove RegexpIter, we don't need it. Signed-off-by: Tom Wilkie * Fix logcli. Signed-off-by: Tom Wilkie * Document the filter expression sytax. Signed-off-by: Tom Wilkie * Fix ingester test. Signed-off-by: Tom Wilkie * Add an extra filter step if the user specifies a regex using old API. Signed-off-by: Tom Wilkie * Better error messages. Signed-off-by: Tom Wilkie * Review feedback. Signed-off-by: Tom Wilkie * link to helm/README.md * Typo * Add two more links to readme (#560) * Close all chunks before flushing. Moved the check for already closed to make sure we honor this check when `immediate` flushing is requested * beginnings of label extraction pipeline * starting to add label extraction, super rough but need to do some work in a different branch * Adds json log entry parser with configuration. * rebase to the new structure * Plug the log entry pipeline into promtail Co-authored-by: Edward Welch * Polish json entry stage * adding regex pipeline stage * updating tests adding CRI and Docker format pipeline stage extensions adding backwards compatibility with current config * adding benchmarks * adding a pipeline processing histogram * fixing capitalization on CRI stage and some lints * Updating helm/ksonnet to use new pipeline config Updating docs Rebase fixes * Remove unnecessarily long wait times in tests. Signed-off-by: Tom Wilkie * Explictly listen on localhost in tests, to stop warning on MacOS. Signed-off-by: Tom Wilkie * Update vendor for weaveworks/commont to Tom's fork, for now. Signed-off-by: Tom Wilkie * rename __filename__ label to filename * fix review feedback * Add a histogram for chunk encoding time (#565) Signed-off-by: Goutham Veeramachaneni * add optional PodDisruptionBudget to helm chart (#515) * add optional PodDisruptionBudget to helm chart * address comments * add back new line - no change to helpers template * fix silly typo in loki-stack version * Fix a bug where we should use the glob matcher on fsnotify new file create. Changed the timing of the sync function in the unit test to fix flakiness in the test. * Support using an IPv6 in the Loki push url (#566) * Clean up the metric for pipeline duration to keep it within the pipeline file, also changing unit to seconds and namespace to logentry * initial checkin mostly working, need to extract out the config needs a proper ksonnet or helm deployment or both needs a makefile * improving metrics improving tests config via flags added ksonnet config * Add support for memcaches (#564) * vendor: update cortex Don't be blocked on https://github.com/cortexproject/cortex/pull/1345 to be merged and still maintain the fork Signed-off-by: Goutham Veeramachaneni * add memcached ksonnet Signed-off-by: Goutham Veeramachaneni * commit generated proto Signed-off-by: Goutham Veeramachaneni * fix minor issues with memcached config in ksonnet (#578) Signed-off-by: Goutham Veeramachaneni * Add LICENSE * using an environment variable passed into an arg instead of reading the pod name from a file and the downardApi added a makefile * adding namespace to ksonnet config, moved images into a config file * fixing how auth is applied * change response_latency bucket sizes * changing response_latency buckets some more, making exponential and configurable * Limiting query start time with config (#572) * Limiting query start time with config * Fixed maxLookBackPeriod check, added it to existing configs, some other fixes * gofmted file * Changed maxLookBackPeriod to 4 weeks in helm chart * Setting maxLookBackPeriod in helm chart to 0 and bumping up the helm chart version * changed maxLookBackPeriod in yaml in cmd to 0 and some nit * Update table manager image in production/ksonnet (#582) * Create CODE_OF_CONDUCT.md (#516) * Add a pull request template (#517) * Helm: Allow custom pipeline stages (#580) Signed-off-by: Steven Sheehy * adds external labels to be passed via flags (#510) * impr/logcli: Added label output filters + tests (#563) * impr/logcli: Added label filters + tests * Address review * udpate readme * updating README * adding diagram * impr/clients: Handle TLS config and MTLS for logcli and promtail (#540) * impr/clients: Handle TLS config and MTLS for logcli and promtail * fix/tls: Please gofmt... * impr/clients: use prometheus HTTPClientConfig for logcli and promtail * fix/promtail: Set proper Client config name * impr/promtail: Use prometheus HTTPClientConfig configuration * adapt with master * address review * fix conflicts * address requested changes * remove file Signed-off-by: Goutham Veeramachaneni * Change tail response for backward compatibilty with future changes (#590) Changed it to dict with single key called "streams" and value set to list of logproto.Stream * updating to match websocket api changes * fixes test in circle ci getting OOMKilled (#593) * Improve readiness probe output (#556) Signed-off-by: Steven Sheehy * bump up promtail chart version Signed-off-by: Xiang Dai <764524258@qq.com> * fixes chunks lazy loading (#595) * fixes ingester querier not honoring filters (#594) * Get rid of the cortex fork with lazy loading upstreamed (#596) Signed-off-by: Goutham Veeramachaneni * Fix local config: Use DayTime (#598) * Fix local config: Use DayTime Psst, the date is the first commit date for loki ;) Signed-off-by: Goutham Veeramachaneni * Fix the config in ksonnet and helm too Signed-off-by: Goutham Veeramachaneni * Typo (#588) Fix typo Signed-off-by: Goutham Veeramachaneni * need to bump helm chart after PR #598 * Update operations.md (#615) Small update to fix the link to the Cortex project. * Also bumping lok-stack version which needs to be done if the loki or promtail chart versions are changed (#612) * Added namespace to helm install notes (#617) * This add make target to deploy a dev version using helm (#586) * add a dev target to deploy the current image in k8s * impr/clients: Handle TLS config and MTLS for logcli and promtail (#540) * impr/clients: Handle TLS config and MTLS for logcli and promtail * fix/tls: Please gofmt... * impr/clients: use prometheus HTTPClientConfig for logcli and promtail * fix/promtail: Set proper Client config name * impr/promtail: Use prometheus HTTPClientConfig configuration * adapt with master * address review * fix conflicts * address requested changes * remove file * add helm dev targets * adding back assets * fix review comments * Review feedback * Update cortex vendor (#610) * Update cortex vendor Use query max look back from cortex Update config changes from cortex Fixed breaking code due to updating cortex vendor * fixed linter error * Changes for running Table Manager with loki in single binary (#600) * Update readme (loki-stack) * ksonnet changes for running loki in single binary (#622) * ksonnet changes for running loki in single bianry Added retention config with default values * Fixed indentation * provide Cassandra Index Store Example (#625) Mentioned in title. To save new beginner's time, provide one config example for use Cassandra as Index Storage. * Helm chart tracing variable fix (#621) * loki chart deployment.yaml: Only set JAEGER_AGENT_HOST if set. * docs/troubleshooting.md: Fixed variable name for chart option. * Bumped loki chart version for variable fix. * Switch Loki to StatefulSet (#585) Signed-off-by: Steven Sheehy * Update details about logs retention * Limits: Reject entries based on age set in limits (#631) * Reject entries based on age set in limits * Save people time until #535 is resolved. * working version with Gatherer * better counters * implements json stage metrics * adds test for json metrics * adds matchers and metrics to regex and json * tidy up * add more memory to circle ci * tweaking test target * fix typo * move custom metrics to /metrics and prefix them * fix linter * Refactor to make everything a stage. Still needs: Matcher stage work, pipeline test work * Making the pipeline itself a Stage so that we can use it to better implement the Match stage (and it cleans up the Docker and CRI extensions some too) Still needs to fix the metrics test * implementing all the functions for the counter and gauge metric types metric test is still failing because of missing metrics when the counter is 0 added a lot of TODO's I need to go back and cleanup * cleaned up most of the TODO's refactored and improved some of the tests, each stage type should now have a test using actual YAML A few TODO's remaining and some comment cleanup * cleaning up remaining TODO's, adding tests cleaning up GoDoc pipeline_name is now optional for matcher stage * Remove LogCount * fix flaky timestamp test * PR feedback * renaming `metric` stage to `metrics` as it defines multiple metrics, similar to labels stage which is also plural. Adding a couple unit tests to regex and json stage to act as examples * fix labels for PodDisruptionBudget on helm (#623) * updating docs for new pipeline config. removed helm entry in scrape_config.sh because there doesn't seem to be anyway to make it work with new pipeline config * PR Feedback * adding a release process * also restrict the release to master branch only (not sure if this is actually necessary) * change the helm pullPolicy since we will be using releases now * updating versions for loki v0.1.0 * release stage is broken, removing for now * Remove label __name__ from store querier (#648) * chore(vendor): update cortex vendor Updates cortex vendor to get the changes from cortexproject/cortex#1431. Required for making promtail build on Windows Signed-off-by: sh0rez * feat(ci): promtail cross platform Build promtail on linux and windows, discard artifacts * Remove 404 link (#637) Signed-off-by: Xiang Dai <764524258@qq.com> * feat(promtail): initContainers (#655) * fix(promtail/targets): remove dependency on prometheus/relabel `filetargetmanager.go` had a dependency on prometheus/relabel, a package that has been removed in favor of prometheus/pkg/relabel. This converts the code to the new package, to allow the prometheus vendor be updated to master * chore(vendor): update prometheus vendor Updates prometheus vendor to current master, to add support for InitContainers in kubernetes service discovery * chore(vendor): do dep's homework Gives dep hints on how to resolve the vendor so that it work * fix(promtail/targets): non-nil check Accidentally checked against the wrong labelSet, this one can never get nil * fix(loki): honor log level from config file (#657) Because of the logger being initialized before the configuration file is parsed, the log_level from the config file is ignored. To solve this, the logger is reinitialized after the file is parsed, as it is already being done in promtail. * add support for RFC3339Nano in query timestamps (#656) * refactoring things so that the comparator can use the reader to make a direct query to loki to look for logs not received over the websocket before reporting them as missing * Helm: Integration testing (#641) * Helm chart integration testing Signed-off-by: Steven Sheehy * Don't check helm version on every push Signed-off-by: Steven Sheehy * Remove chart upgrade testing Signed-off-by: Steven Sheehy * Add dynamodb sample for overriding default provisioning capacity units (#626) * adding a list of received entries (acknowledged) to use for comparison against entries which were not expected so that we can report them as duplicates. * Docker Logging Driver (#663) * adds first version of docker driver * without logrus and fixes some linter issue * fix the driver and start a build system * adds swarm label discovery * Add documentation and more targets * make the linter happy :heart: * indent config.json * with circleci steps for master and branch * Review Feebacks * fix docker plugin ci (#664) * fix docker plugin ci * use binary cache * Fix publish-helm failure (#665) Signed-off-by: Steven Sheehy * rename fluent plugin and update docs * Removing the pre-allocation of a buffer when serializing blocks, in most of my empirical testing we were using 9-10k out of the 32k allocated leaving about 2/3 of the buffer allocated and unused times the number of blocks per chunk, times the number of chunks kept in memory. This was adding up to a fair amount of allocated but unused space. * fix missing logger in client (#673) * updating the loki dashboards to use the metrics from the new gateway * fix helm lint issue Signed-off-by: Xiang Dai <764524258@qq.com> * Improvements in live tailing of logs (#541) * Improvements in live tailing of logs Instead of polling for new logs, a grpc stream is opened between ingester and querier to get live logs Querier reconnects to disconnected or newly added ingesters * Added more comments to code for live log tailing * Some code refactoring in live log tailing * handling delayfor in logcli, max delayfor to be 5 seconds * some changes in tail response in live tailing * Fixed issue with stopping ingesters gracefully when live tailing is being used * Added tests for tailer in querier * Live tailing made logql compatible, some code refactoring suggested in PR * Fix helm test error Signed-off-by: Xiang Dai <764524258@qq.com> * Update chart version Signed-off-by: Xiang Dai <764524258@qq.com> * Removed test for tailer in querier due to issues with synchronization * adding resource requests in jsonnet * changing the default prune interval to 60 seconds, at the previous 1 second it would cause some way too aggressive querying when scaled out over all our clusters and loki had a hiccup * fix logcli code src path * changing the log length histogram to be a normal histogram with only a `path` label, also removing the label values when no longer tailing the file. Following the same pattern we used for readBytes and totalBytes. * removing entries.go as we are no longer using the custom Histogram for the log_entries_bytes histogram * Add selector as required by k8s 1.8 and higher. (#716) Fixes #715 * fluent-plugin: Mark as multi-workers ready (#709) * fluent-plugin: Mark as multi-workers ready * fluent-plugin: Add info on multi-worker usage to README * sync with Cortex for s3 path style url (#705) * fix(loki|promtail): logger re-init nil config panic (#697) When a more or less invalid config (e.g. `null`) is supplied, the log level prop of the config receives an invalid value which causes the logger to panic on re-init. Prevents this by checking for a nil log-level and notifies the user in case * BREAKING fix(loki-mixin): rename rules key (#691) Renames the `prometheus_rules` key to `prometheusRules` to comply to the spec (https://github.com/monitoring-mixins/docs/blob/master/design.pdf) BREAKING `prometheus_rules` is not available anymore * update grafana to fix dashboard provider (#674) * fluent-plugin: Add separate license to fluent-plugin-grafana-loki to fix gem installation (#682) * Fixed orderedDeps() order stability (#721) * ability to specify keys to remove (#669) * feat(docker): multi-arch Dockerfile (#668) Adds an entirely new Dockerfile to the repository root which is capable of: - building promtail and loki from the same image - based on `scratch`, so that the final image can be executed on every supported GOARCH Please note that this Dockerfile should always be built using BuildKit (`buildctl` or `DOCKER_BUILDKIT=1` in recent versions) for maximum performance, as BuildKit's DAG allows for smart skipping of uneeded stages. These changes were proposed in #659 * fix(loki): panic on missing config (#720) * fix(loki): pass missing config error to user Missing config errors are handled at the library level. Our own check mitigated this and causes loki to SEGFAULT later on * feat(loki): default config file in container The container provides a default config file. Use it by default * Revert "fix(loki): pass missing config error to user" This reverts commit b2744fcf427b2b386dce5e999c855ae5c899e4e2, because loki it assumed loki was incapable of running without config, which is not the case. * move Dockerfile multi-arch to build and ignore that folder (#723) * move Dockerfile multi-arch to build and ignore that folder * docker-driver fix * Query label values and names are now fetched from the store. (#521) * Query label values and names are now fetched from the store. A time range is now required by the /api/prom/label with a sane default (6 hours from now). * fix http querystring and update doc * update vendor * rebased * Typo on values.yaml (#728) * prune interval is configurable canary will suspend all operations on SIGINT but not exit, allowing you to shutdown the canary without it being restarted by docker/kubernetes SIGTERM will shutdown everything and end the process * Add support to timestamp stage to parse Unix seconds, milliseconds, and nanosecond timestamps * Redirect / to /targets in promtail server * Fixed RFC3339Nano examples in doc * use strconf.FormatFloat instead of fmt.Sprintf for converting floats to strings, this way we can eliminate non significant trailing zeros such that the float value 1 would be "1" as a string instead of "1.000000" * adding a golang Template stage * Documented /ready, /metrics and /flush endpoints (#743) * feat(logcli): query from absolute timestamp (#736) * feat(logcli): query from absolute timestamp Adds a new flag (`--from`) as to complement `--since`. While since subtracts a relative duration from the current time, from allows to specify the absolute start of the lookback window. Note: `--from` takes precedence over `--since`, but only if set. * fix(logcli): use RFC3339Nano for -from To comply with Prometheus, this flag now honors Nanoseconds as well (was using RFC3339 so far) * Added source support to regex and json stages * Converted source in regex and josn stages to string pointer * Added source validation to regex and json stages * Parallelly run regex and json stages pipeline tests * feat(logcli): output modes (#731) * feat(logcli): quiet mode Adds a quiet mode (-q / --quiet) to suppress the debug messages to stderr * feat(logcli): output modes Adds two alternative output modes (-o / --output) - raw: emits the line as parsed - jsonl: emits the line plus all known metadata as JSONL (JSON Line) Usage: -o [default, raw, jsonl] * feat(logcli): quiet tailing mode * feat(logcli): output modes while tailing Supports the three different output modes in tail mode as well * feat(logcli): print labels in jsonl tail mode * refactor(logcli): clean up entry printing Moves the entry printing into a standardized interface, implements this three times: - default (human readable) - jsonl (for scripts) - raw ('as is') * fluentd-plugin-grafana-loki: change log.info to log.debug (#751) Reduces background chatter which in turn can trigger more log writes Signed-off-by: Brian Candler * fluentd-plugin-grafana-loki: avoid exception when remove/label_keys is unset (#750) Fixes #749 Signed-off-by: Brian Candler * Added a note about regex accepted syntax in the filter expression (#746) * cleanup rake warnings, bump version * promtail: Add systemd journal support (#730) Support for reading systemd journal entries has been added. promtail will look for a job in scrape_configs with a journal key to activate the journal target. If GOOS=linux and CGO_ENABLED=1, promtail will now require libsystemd headers to be available for building. If GOOS is not linux or CGO_ENABLED is not 1, journal support will be unavailable and a log message will be printed warning the user that their config file has journal tailing configured without it being built into promtail. See docs/promtail-examples.md for a concrete example of using journal support. Other structural changes made: 1. Ability for checking if scrape.Config.ServiceDiscoveryConfig is non-zero has been added. This was chosen over making ServiceDiscoveryConfig a pointer as yaml.v2 cannot parse an inline struct into a pointer value. 2. Updated pipeline logger component name to journal_pipeline and file_pipeline for JournalTargetManager and FileTargetManager respectively. 3. The positions file will now store positions as strings instead of integers. Existing positions will be read in properly but written out as strings the next time the positions file is saved. This is done to be able to store the journal cursor, which is a string. The positions API has been updated to support reading in the old integer values and the new string values. * Rollback changes to Makefile and build/Dockerfile from #730 (#758) This commit rolls back the changes to the Makefile and build/Dockerfile that caused CGO_ENABLED=1 to be present during some builds. This commit causes the journal support to be disabled in any build produced by make. Journal support can still be enabled in a manual build: go build -o cmd/promtail/promtail cmd/promtail * Storage memory improvement (#713) * add benchmark for storage queries * improve iterator to load only on next * fix memory retained by lazy chunks * reverse backward lazy iterator * fixed helm installation instructions (#761) * Added date without year support to timestamp stage (#760) * Documented timestamp's custom format syntax (#763) * Added tail length limit to limit duration of live tailing of logs to 1 hour (#756) * Added tail length limit to limit duration of live tailing of logs to 1 hour * Some code refactoring suggested from PR review for live tailing duration limit * Fixed error messages in live tailing of logs * Fixed lint errors * preparing for move into loki repo * finishing up loki-canary move into loki repo * rounds nanoseconds boundaries to milliseconds (#771) * rounds nanoseconds boundaries to milliseconds * convert also store query * feat(logcli): add --to flag to specify latest RFC3339 time for query (#776) Fixes #774 * Parse the addr into a URL so we can extract the Host name for use in the TLSConfig (#778) * fix path escape (#779) * better job of fixing url parsing and host name extraction for logcli * feat(loki): extended tailing (#764) * refactor(querier/ingester): TailRequest Lookback window Moves the specifications of the Lookback Window out of the logproto.QueryRequest into it's own type logproto.Lookback. This is required, because the Lookback Window will be used in the TailRequest as well. * feat(querier): parse Lookback from HTTP Request * feat(logcli): send Lookback Window spec with tail request * feat(querier): include historic entries in tail mode Extends tailing by sending a configurable amount of historic entries with before the live entries. This enables a behaviour that is closer to kubectl logs -f and docker logs -f. It is implemented by running a regular Query before subscribing to the ingesters. * fix: adapt tests to Lookback change * feat(querier): check all errors to make the linter happy * fix(logproto): flatten Lookback window spec Flattens the Lookback window spec into the individual queries * fix(ingester): adapt test to Lookback flatten * adjust old instructions for troubleshooting docker daemon (#785) * promtail: clarify linux build instructions in docs * Use prometheus pool for line buffer. (#790) * Use prometheus pool for line buffer. * Document centos dep - document centos dep - add `-y` option Signed-off-by: Xiang Dai <764524258@qq.com> * add missing ` Signed-off-by: Xiang Dai <764524258@qq.com> * fix: Speed up Loki shutdown when using the sample local config (#784) * adding ability to supply timezone to timestamp pipeline stage * ingester: support chunk transfers on ingester shutdown. This commit introduces chunk transfers, borrowing the mechanism from Cortex's implementation: when an ingester is shut down with claim on rollout enabled, the ingester will find a pending ingester and transfer all of its chunks to it. * ingester: fix lint issues for chunk transfers * ingester: Add test for chunk transfers * add a Name() method to the stage interface so that debug logging can show you the name of the pipeline stage which just processed the log remove some unnecessary logging around fsnotify events we don't care about and saving positions Make the Processing Log Lines doc a first class citizen, I reference this a lot and currently it's hidden behind 3 clicks * ingester: clean up chunk transfer code * ingester: fix feedback from PR review * ingester: log error if closing client after transfer fails * Added -querier.query_timeout support (#788) * Add prometheus for metrics and upgrade some of the outdated gems. (#792) * Fix broken link in readme file * fix dependencies order and bump version (#803) * promtail: restore ability to show target labels in promtail UI PR #791 accidentally removed the ability to use the promtail UI by removing methods from the Target interface that were only used within the HTML templates. Along with restoring the methods in the Target interface, this commit also introduces details for the JournalTarget, which currently only provides the position in the journal being tracked. * ingester: register Ingester service in gRPC on loki start Registering the Ingester service to gRPC enables the chunk transfer mechanism to work. * Simplify our makefile as much as possible (#753) refactor(makefile): simplify makefile by removing the autogenerated targets and make building binaries and dockerfiles separate operations. * fix panic in docker driver for newer docker version (18.09.7+) (#813) * docker-driver-push does a build of all the go files and as such needs to make called with BUILD_IN_CONTAINER=false from circleci * fix tail library logs to use our own log format (#579) * fix tail library logs to use our own log format * PR Feedbacks * Update logcli usage in docs and improve help text --- .circleci/config.yml | 111 +- .github/pull_request_template.md | 19 + .gitignore | 8 + .golangci.yml | 66 + .gometalinter.json | 35 - CODE_OF_CONDUCT.md | 76 + CONTRIBUTING.md | 5 + Gopkg.lock | 354 +- Gopkg.toml | 10 +- Makefile | 426 +- README.md | 11 +- build/Dockerfile | 53 + cmd/docker-driver/Dockerfile | 5 + cmd/docker-driver/README.md | 167 + cmd/docker-driver/config.go | 296 + cmd/docker-driver/config.json | 20 + cmd/docker-driver/driver.go | 200 + cmd/docker-driver/http.go | 95 + cmd/docker-driver/loki.go | 70 + cmd/docker-driver/main.go | 46 + cmd/docker-driver/pipeline-example.yaml | 5 + cmd/logcli/client.go | 92 +- cmd/logcli/main.go | 52 +- cmd/logcli/output.go | 73 + cmd/logcli/query.go | 158 +- cmd/logcli/query_test.go | 130 + cmd/logcli/tail.go | 54 +- cmd/logcli/utils.go | 97 + cmd/loki-canary/Dockerfile | 14 + cmd/loki-canary/main.go | 78 + cmd/loki/Dockerfile | 17 +- cmd/loki/Dockerfile.debug | 28 + cmd/loki/loki-local-config.yaml | 29 +- cmd/loki/main.go | 19 + cmd/promtail/Dockerfile | 18 +- cmd/promtail/Dockerfile.debug | 28 + cmd/promtail/main.go | 11 +- cmd/promtail/promtail-docker-config.yaml | 5 +- cmd/promtail/promtail-local-config.yaml | 5 +- debug/README.md | 57 + debug/docker-compose.yaml | 37 + docs/api.md | 45 +- docs/canary/README.md | 108 + docs/canary/block.png | Bin 0 -> 56500 bytes docs/logcli.md | 56 +- docs/logentry/processing-log-lines.md | 621 + docs/operations.md | 62 +- docs/promtail-api.md | 22 + docs/promtail-examples.md | 99 +- docs/promtail-setup.md | 107 +- docs/promtail.md | 46 +- docs/troubleshooting.md | 41 +- docs/usage.md | 23 +- .../.gitignore | 0 .../.rspec | 0 .../.rubocop.yml | 0 .../Dockerfile | 0 .../Gemfile | 2 + fluentd/fluent-plugin-grafana-loki/LICENSE | 202 + .../README.md | 40 +- .../Rakefile | 2 + .../bin/console | 0 .../bin/setup | 0 .../fluent-plugin-grafana-loki/docker/Gemfile | 9 + .../docker/conf/fluentd-1.conf | 0 .../docker/conf/fluentd-2.conf | 0 .../docker/conf/fluentd.conf | 0 .../docker/conf/loki.conf | 0 .../docker/conf/systemd.conf | 0 .../docker/docker-compose.yml | 0 .../docker/entrypoint.sh | 0 .../fluent-plugin-grafana-loki.gemspec} | 8 +- .../lib/fluent/plugin/out_loki.rb | 22 +- .../spec/gems/fluent/plugin/data/syslog | 0 .../spec/gems/fluent/plugin/data/syslog2 | 0 .../gems/fluent/plugin/loki_output_spec.rb | 2 + .../spec/spec_helper.rb | 2 + fluentd/fluent-plugin-loki/docker/Gemfile | 5 - loki-build-image/Dockerfile | 43 +- pkg/canary/comparator/comparator.go | 273 + pkg/canary/comparator/comparator_test.go | 276 + pkg/canary/reader/reader.go | 231 + pkg/canary/writer/writer.go | 82 + pkg/chunkenc/dumb_chunk.go | 3 +- pkg/chunkenc/facade.go | 2 +- pkg/chunkenc/gzip.go | 190 +- pkg/chunkenc/gzip_test.go | 108 +- pkg/chunkenc/interface.go | 3 +- pkg/chunkenc/lazy_chunk.go | 108 + pkg/chunkenc/pool.go | 95 + pkg/distributor/distributor.go | 28 +- pkg/ingester/chunk_test.go | 8 +- pkg/ingester/client/client.go | 10 +- pkg/ingester/flush.go | 102 +- pkg/ingester/flush_test.go | 44 +- pkg/ingester/ingester.go | 103 +- pkg/ingester/ingester_test.go | 20 +- pkg/ingester/instance.go | 137 +- pkg/ingester/stream.go | 97 +- pkg/ingester/stream_test.go | 8 +- pkg/ingester/tailer.go | 244 + pkg/ingester/transfer.go | 236 + pkg/ingester/transfer_test.go | 210 + pkg/iter/iterator.go | 163 +- pkg/iter/iterator_test.go | 39 +- pkg/logentry/metric/counters.go | 76 + pkg/logentry/metric/gauges.go | 83 + pkg/logentry/metric/histograms.go | 59 + pkg/logentry/metric/metricvec.go | 50 + pkg/logentry/stages/extensions.go | 66 + pkg/logentry/stages/extensions_test.go | 160 + pkg/logentry/stages/json.go | 160 + pkg/logentry/stages/json_test.go | 358 + pkg/logentry/stages/labels.go | 87 + pkg/logentry/stages/labels_test.go | 164 + pkg/logentry/stages/match.go | 100 + pkg/logentry/stages/match_test.go | 162 + pkg/logentry/stages/metrics.go | 265 + pkg/logentry/stages/metrics_test.go | 325 + pkg/logentry/stages/output.go | 79 + pkg/logentry/stages/output_test.go | 111 + pkg/logentry/stages/pipeline.go | 113 + pkg/logentry/stages/pipeline_test.go | 170 + pkg/logentry/stages/regex.go | 128 + pkg/logentry/stages/regex_test.go | 337 + pkg/logentry/stages/stage.go | 101 + pkg/logentry/stages/template.go | 130 + pkg/logentry/stages/template_test.go | 205 + pkg/logentry/stages/timestamp.go | 109 + pkg/logentry/stages/timestamp_test.go | 235 + pkg/logentry/stages/util.go | 159 + pkg/logentry/stages/util_test.go | 197 + pkg/logproto/dep.go | 2 +- pkg/logproto/logproto.pb.go | 3505 +- pkg/logproto/logproto.proto | 46 + pkg/logql/ast.go | 129 + pkg/logql/expr.y | 65 + pkg/logql/expr.y.go | 567 + pkg/logql/parser.go | 118 + pkg/logql/parser_test.go | 157 + pkg/loki/loki.go | 55 +- pkg/loki/modules.go | 132 +- pkg/loki/modules_test.go | 18 +- pkg/parser/labels.go | 548 - pkg/parser/labels.y | 63 - pkg/parser/parser.go | 125 - pkg/parser/parser_test.go | 98 - pkg/promtail/client/client.go | 91 +- pkg/promtail/client/config.go | 67 + pkg/promtail/client/fake/client.go | 24 + pkg/promtail/client/multi.go | 48 + pkg/promtail/client/multi_test.go | 103 + pkg/promtail/config/config.go | 7 +- pkg/promtail/positions/positions.go | 73 +- pkg/promtail/promtail.go | 23 +- pkg/promtail/promtail_test.go | 47 +- pkg/promtail/scrape/scrape.go | 23 + pkg/promtail/scrape/scrape_test.go | 72 + pkg/promtail/server/server.go | 205 + pkg/promtail/server/template.go | 96 + pkg/promtail/server/ui/assets_generate.go | 24 + pkg/promtail/server/ui/assets_vfsdata.go | 767 + pkg/promtail/server/ui/doc.go | 9 + .../server/ui/static/css/promtail.css | 31 + pkg/promtail/server/ui/static/css/targets.css | 41 + pkg/promtail/server/ui/static/img/favicon.ico | Bin 0 -> 225342 bytes pkg/promtail/server/ui/static/js/targets.js | 64 + .../bootstrap-4.1.3/css/bootstrap-grid.css | 1912 + .../css/bootstrap-grid.css.map | 1 + .../css/bootstrap-grid.min.css | 7 + .../css/bootstrap-grid.min.css.map | 1 + .../bootstrap-4.1.3/css/bootstrap-reboot.css | 331 + .../css/bootstrap-reboot.css.map | 1 + .../css/bootstrap-reboot.min.css | 8 + .../css/bootstrap-reboot.min.css.map | 1 + .../vendor/bootstrap-4.1.3/css/bootstrap.css | 9030 ++++ .../bootstrap-4.1.3/css/bootstrap.css.map | 1 + .../bootstrap-4.1.3/css/bootstrap.min.css | 7 + .../bootstrap-4.1.3/css/bootstrap.min.css.map | 1 + .../bootstrap-4.1.3/js/bootstrap.bundle.js | 6461 +++ .../js/bootstrap.bundle.js.map | 1 + .../js/bootstrap.bundle.min.js | 7 + .../js/bootstrap.bundle.min.js.map | 1 + .../vendor/bootstrap-4.1.3/js/bootstrap.js | 3944 ++ .../bootstrap-4.1.3/js/bootstrap.js.map | 1 + .../bootstrap-4.1.3/js/bootstrap.min.js | 7 + .../bootstrap-4.1.3/js/bootstrap.min.js.map | 1 + .../bootstrap3-typeahead.min.js | 21 + .../css/bootstrap-glyphicons.css | 809 + .../css/bootstrap-glyphicons.min.css | 6 + .../fonts/fontawesome/fa-brands-400.eot | Bin 0 -> 98620 bytes .../fonts/fontawesome/fa-brands-400.svg | 1008 + .../fonts/fontawesome/fa-brands-400.ttf | Bin 0 -> 98384 bytes .../fonts/fontawesome/fa-brands-400.woff | Bin 0 -> 63712 bytes .../fonts/fontawesome/fa-brands-400.woff2 | Bin 0 -> 54420 bytes .../fonts/fontawesome/fa-regular-400.eot | Bin 0 -> 31156 bytes .../fonts/fontawesome/fa-regular-400.svg | 366 + .../fonts/fontawesome/fa-regular-400.ttf | Bin 0 -> 30928 bytes .../fonts/fontawesome/fa-regular-400.woff | Bin 0 -> 14712 bytes .../fonts/fontawesome/fa-regular-400.woff2 | Bin 0 -> 12220 bytes .../fonts/fontawesome/fa-solid-900.eot | Bin 0 -> 102152 bytes .../fonts/fontawesome/fa-solid-900.svg | 1467 + .../fonts/fontawesome/fa-solid-900.ttf | Bin 0 -> 101932 bytes .../fonts/fontawesome/fa-solid-900.woff | Bin 0 -> 48704 bytes .../fonts/fontawesome/fa-solid-900.woff2 | Bin 0 -> 38784 bytes .../glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../glyphicons-halflings-regular.svg | 288 + .../glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../maps/glyphicons-fontawesome.css | 2947 ++ .../maps/glyphicons-fontawesome.less | 3891 ++ .../maps/glyphicons-fontawesome.min.css | 1 + .../ui/static/vendor/js/jquery-3.3.1.min.js | 2 + .../ui/static/vendor/js/jquery.hotkeys.js | 113 + .../server/ui/static/vendor/js/jquery.min.js | 4 + .../ui/static/vendor/js/jquery.selection.js | 354 + .../server/ui/static/vendor/js/popper.min.js | 5 + pkg/promtail/server/ui/templates/_base.html | 56 + .../ui/templates/service-discovery.html | 92 + pkg/promtail/server/ui/templates/targets.html | 104 + pkg/promtail/server/ui/ui.go | 36 + pkg/promtail/targets/filetarget.go | 66 +- pkg/promtail/targets/filetarget_test.go | 34 +- pkg/promtail/targets/filetargetmanager.go | 159 +- pkg/promtail/targets/journaltarget.go | 221 + pkg/promtail/targets/journaltarget_test.go | 112 + pkg/promtail/targets/journaltargetmanager.go | 45 + .../targets/journaltargetmanager_linux.go | 96 + pkg/promtail/targets/manager.go | 74 +- pkg/promtail/targets/tailer.go | 19 +- pkg/promtail/targets/target.go | 76 + pkg/querier/http.go | 152 +- pkg/querier/querier.go | 213 +- pkg/querier/querier_mock_test.go | 229 + pkg/querier/querier_test.go | 208 + pkg/querier/store.go | 104 - pkg/querier/tail.go | 362 +- pkg/storage/hack/main.go | 142 + pkg/storage/store.go | 273 + pkg/storage/store_test.go | 163 + pkg/util/conv.go | 50 +- pkg/util/conv_test.go | 59 + pkg/util/errors.go | 48 + pkg/util/flagext/labelset.go | 80 + pkg/util/log.go | 74 + pkg/util/mock.go | 21 + pkg/util/ring.go | 11 + production/README.md | 33 +- production/helm/README.md | 67 +- production/helm/loki-stack/Chart.yaml | 2 +- production/helm/loki-stack/requirements.yaml | 9 +- .../helm/loki-stack/templates/_helpers.tpl | 32 + .../loki-stack/templates/datasources.yaml | 30 + .../templates/tests/loki-test-configmap.yaml | 42 + .../templates/tests/loki-test-pod.yaml | 30 + production/helm/loki-stack/values.yaml | 10 + production/helm/loki/Chart.yaml | 2 +- production/helm/loki/templates/NOTES.txt | 2 +- production/helm/loki/templates/_helpers.tpl | 1 - production/helm/loki/templates/pdb.yaml | 16 + production/helm/loki/templates/pvc.yaml | 22 - .../helm/loki/templates/service-headless.yaml | 19 + .../{deployment.yaml => statefulset.yaml} | 49 +- production/helm/loki/values.yaml | 53 +- production/helm/promtail/Chart.yaml | 2 +- production/helm/promtail/templates/NOTES.txt | 4 +- .../helm/promtail/templates/configmap.yaml | 253 +- .../helm/promtail/templates/daemonset.yaml | 16 +- production/helm/promtail/values.yaml | 227 +- production/ksonnet/README.md | 16 +- .../ksonnet/loki-canary/config.libsonnet | 5 + .../ksonnet/loki-canary/jsonnetfile.json | 14 + .../ksonnet/loki-canary/loki-canary.libsonnet | 27 + production/ksonnet/loki/config.libsonnet | 78 +- production/ksonnet/loki/images.libsonnet | 6 +- production/ksonnet/loki/jsonnetfile.json | 10 + production/ksonnet/loki/loki.libsonnet | 7 +- production/ksonnet/loki/memcached.libsonnet | 21 + .../ksonnet/loki/table-manager.libsonnet | 28 +- production/ksonnet/promtail/config.libsonnet | 24 +- .../ksonnet/promtail/promtail.libsonnet | 13 +- .../ksonnet/promtail/scrape_config.libsonnet | 38 +- production/loki-mixin/dashboards.libsonnet | 12 +- .../loki-mixin/recording_rules.libsonnet | 2 +- tools/dev.values.yaml | 25 + tools/helm.yaml | 37 + tools/increment_version.sh | 77 + tools/promtail.sh | 74 +- tools/release_prepare.sh | 75 + tools/scrape_config.sh | 10 +- .../diskv => Azure/go-ansiterm}/LICENSE | 4 +- vendor/github.com/Azure/go-ansiterm/README.md | 12 + .../github.com/Azure/go-ansiterm/constants.go | 188 + .../github.com/Azure/go-ansiterm/context.go | 7 + .../Azure/go-ansiterm/csi_entry_state.go | 49 + .../Azure/go-ansiterm/csi_param_state.go | 38 + .../go-ansiterm/escape_intermediate_state.go | 36 + .../Azure/go-ansiterm/escape_state.go | 47 + .../Azure/go-ansiterm/event_handler.go | 90 + .../Azure/go-ansiterm/ground_state.go | 24 + .../Azure/go-ansiterm/osc_string_state.go | 31 + vendor/github.com/Azure/go-ansiterm/parser.go | 151 + .../go-ansiterm/parser_action_helpers.go | 99 + .../Azure/go-ansiterm/parser_actions.go | 119 + vendor/github.com/Azure/go-ansiterm/states.go | 71 + .../github.com/Azure/go-ansiterm/utilities.go | 21 + .../Azure/go-ansiterm/winterm/ansi.go | 182 + .../Azure/go-ansiterm/winterm/api.go | 327 + .../go-ansiterm/winterm/attr_translation.go | 100 + .../go-ansiterm/winterm/cursor_helpers.go | 101 + .../go-ansiterm/winterm/erase_helpers.go | 84 + .../go-ansiterm/winterm/scroll_helper.go | 118 + .../Azure/go-ansiterm/winterm/utilities.go | 9 + .../go-ansiterm/winterm/win_event_handler.go | 743 + .../github.com/Microsoft/go-winio/.gitignore | 1 + vendor/github.com/Microsoft/go-winio/LICENSE | 22 + .../github.com/Microsoft/go-winio/README.md | 22 + .../Microsoft/go-winio/archive/tar/LICENSE | 27 + .../github.com/Microsoft/go-winio/backup.go | 280 + vendor/github.com/Microsoft/go-winio/ea.go | 137 + vendor/github.com/Microsoft/go-winio/file.go | 307 + .../github.com/Microsoft/go-winio/fileinfo.go | 61 + vendor/github.com/Microsoft/go-winio/pipe.go | 421 + .../Microsoft/go-winio/privilege.go | 202 + .../github.com/Microsoft/go-winio/reparse.go | 128 + vendor/github.com/Microsoft/go-winio/sd.go | 98 + .../github.com/Microsoft/go-winio/syscall.go | 3 + .../Microsoft/go-winio/zsyscall_windows.go | 520 + vendor/github.com/containerd/fifo/.gitignore | 1 + vendor/github.com/containerd/fifo/.travis.yml | 22 + vendor/github.com/containerd/fifo/LICENSE | 201 + vendor/github.com/containerd/fifo/Makefile | 27 + vendor/github.com/containerd/fifo/fifo.go | 236 + .../containerd/fifo/handle_linux.go | 97 + .../containerd/fifo/handle_nolinux.go | 65 + .../containerd/fifo/mkfifo_nosolaris.go | 25 + .../containerd/fifo/mkfifo_solaris.go | 27 + vendor/github.com/containerd/fifo/raw.go | 116 + vendor/github.com/containerd/fifo/readme.md | 44 + vendor/github.com/coreos/go-systemd/LICENSE | 191 + vendor/github.com/coreos/go-systemd/NOTICE | 5 + .../coreos/go-systemd/activation/files.go | 67 + .../coreos/go-systemd/activation/listeners.go | 103 + .../go-systemd/activation/packetconns.go | 38 + .../coreos/go-systemd/sdjournal/functions.go | 66 + .../coreos/go-systemd/sdjournal/journal.go | 1120 + .../coreos/go-systemd/sdjournal/read.go | 272 + vendor/github.com/coreos/pkg/LICENSE | 202 + vendor/github.com/coreos/pkg/NOTICE | 5 + vendor/github.com/coreos/pkg/dlopen/dlopen.go | 82 + .../coreos/pkg/dlopen/dlopen_example.go | 56 + .../cortex/pkg/chunk/aws/aws_autoscaling.go | 2 +- .../pkg/chunk/aws/dynamodb_storage_client.go | 105 +- .../cortex/pkg/chunk/aws/fixtures.go | 3 + .../pkg/chunk/aws/metrics_autoscaling.go | 52 +- .../cortex/pkg/chunk/aws/s3_storage_client.go | 2 + .../cortex/pkg/chunk/bucket_client.go | 11 + .../cortex/pkg/chunk/cache/background.go | 4 +- .../cortex/pkg/chunk/cache/cache.go | 62 +- .../cortex/pkg/chunk/cache/diskcache.go | 227 - .../cortex/pkg/chunk/cache/fifo_cache.go | 4 +- .../cortex/pkg/chunk/cache/memcached.go | 6 +- .../pkg/chunk/cache/memcached_client.go | 10 +- .../cortex/pkg/chunk/cassandra/fixtures.go | 8 +- .../pkg/chunk/cassandra/storage_client.go | 86 +- .../pkg/chunk/cassandra/table_client.go | 2 +- .../cortexproject/cortex/pkg/chunk/chunk.go | 54 +- .../cortex/pkg/chunk/chunk_store.go | 185 +- .../cortex/pkg/chunk/chunk_store_utils.go | 67 +- .../cortex/pkg/chunk/composite_store.go | 53 +- .../cortex/pkg/chunk/encoding/bigchunk.go | 30 +- .../cortex/pkg/chunk/fixtures.go | 71 +- .../pkg/chunk/gcp/bigtable_index_client.go | 3 - .../pkg/chunk/gcp/bigtable_object_client.go | 8 +- .../cortex/pkg/chunk/gcp/gcs_object_client.go | 14 +- .../cortex/pkg/chunk/gcp/instrumentation.go | 6 +- .../cortex/pkg/chunk/json_helpers.go | 39 +- .../pkg/chunk/local/boltdb_index_client.go | 74 +- .../pkg/chunk/local/boltdb_table_client.go | 28 +- .../cortex/pkg/chunk/local/fixtures.go | 4 +- .../pkg/chunk/local/fs_object_client.go | 39 +- .../cortexproject/cortex/pkg/chunk/schema.go | 338 +- .../cortex/pkg/chunk/schema_caching.go | 6 +- .../cortex/pkg/chunk/schema_config.go | 104 +- .../cortex/pkg/chunk/schema_util.go | 42 +- .../cortex/pkg/chunk/series_store.go | 301 +- .../pkg/{util/wire => chunk/storage}/bytes.go | 2 +- .../pkg/chunk/storage/caching_fixtures.go | 16 +- .../pkg/chunk/storage/caching_index_client.go | 47 +- .../chunk/storage/caching_index_client.pb.go | 180 +- .../chunk/storage/caching_index_client.proto | 8 +- .../cortex/pkg/chunk/storage/factory.go | 61 +- .../cortex/pkg/chunk/storage_client.go | 5 + .../cortex/pkg/chunk/table_manager.go | 152 +- .../cortexproject/cortex/pkg/chunk/tags.go | 58 + .../cortex/pkg/chunk/testutils/testutils.go | 22 +- .../cortex/pkg/ingester/client/client.go | 6 +- .../cortex/pkg/ingester/client/compat.go | 123 +- .../cortex/pkg/ingester/client/cortex.pb.go | 835 +- .../cortex/pkg/ingester/client/cortex.proto | 10 +- .../cortex/pkg/ingester/client/fnv.go | 29 +- .../cortex/pkg/ingester/client/pool.go | 4 +- .../cortex/pkg/ingester/client/timeseries.go | 187 +- .../cortex/pkg/ingester/index/index.go | 188 +- .../cortex/pkg/ring/consul_client.go | 74 +- .../cortex/pkg/ring/consul_client_mock.go | 4 +- .../cortexproject/cortex/pkg/ring/kvstore.go | 37 +- .../cortex/pkg/ring/lifecycler.go | 102 +- .../cortexproject/cortex/pkg/ring/model.go | 2 +- .../cortexproject/cortex/pkg/ring/ring.go | 76 +- .../cortexproject/cortex/pkg/ring/ring.pb.go | 195 +- .../cortex/pkg/util/extract/extract.go | 10 +- .../cortex/pkg/util/flagext/deprecated.go | 26 + .../cortex/pkg/util/flagext/url.go | 8 +- .../cortexproject/cortex/pkg/util/hash_fp.go | 4 +- .../cortexproject/cortex/pkg/util/labels.go | 16 + .../cortexproject/cortex/pkg/util/log.go | 14 +- .../cortex/pkg/util/spanlogger/spanlogger.go | 11 + .../cortex/pkg/util/validation/limits.go | 22 +- .../cortex/pkg/util/validation/override.go | 61 + .../cortex/pkg/util/validation/validate.go | 13 +- vendor/github.com/docker/distribution/LICENSE | 202 + .../registry/api/errcode/errors.go | 267 + .../registry/api/errcode/handler.go | 40 + .../registry/api/errcode/register.go | 138 + vendor/github.com/docker/docker/AUTHORS | 2082 + vendor/github.com/docker/docker/LICENSE | 191 + vendor/github.com/docker/docker/NOTICE | 19 + .../docker/docker/api/types/auth.go | 22 + .../docker/api/types/backend/backend.go | 128 + .../docker/docker/api/types/backend/build.go | 45 + .../docker/docker/api/types/blkiodev/blkio.go | 23 + .../docker/docker/api/types/client.go | 415 + .../docker/docker/api/types/configs.go | 64 + .../docker/api/types/container/config.go | 69 + .../api/types/container/container_changes.go | 21 + .../api/types/container/container_create.go | 21 + .../api/types/container/container_top.go | 21 + .../api/types/container/container_update.go | 17 + .../api/types/container/container_wait.go | 29 + .../docker/api/types/container/host_config.go | 448 + .../api/types/container/hostconfig_unix.go | 41 + .../api/types/container/hostconfig_windows.go | 40 + .../api/types/container/waitcondition.go | 22 + .../docker/docker/api/types/error_response.go | 13 + .../docker/docker/api/types/filters/parse.go | 315 + .../docker/api/types/graph_driver_data.go | 17 + .../docker/docker/api/types/id_response.go | 13 + .../api/types/image_delete_response_item.go | 15 + .../docker/docker/api/types/image_summary.go | 49 + .../docker/docker/api/types/mount/mount.go | 131 + .../docker/api/types/network/network.go | 127 + .../docker/docker/api/types/plugin.go | 203 + .../docker/docker/api/types/plugin_device.go | 25 + .../docker/docker/api/types/plugin_env.go | 25 + .../docker/api/types/plugin_interface_type.go | 21 + .../docker/docker/api/types/plugin_mount.go | 37 + .../docker/api/types/plugin_responses.go | 71 + .../api/types/plugins/logdriver/entry.pb.go | 716 + .../api/types/plugins/logdriver/entry.proto | 16 + .../docker/api/types/plugins/logdriver/gen.go | 3 + .../docker/api/types/plugins/logdriver/io.go | 87 + .../docker/docker/api/types/port.go | 23 + .../docker/api/types/registry/authenticate.go | 21 + .../docker/api/types/registry/registry.go | 119 + .../docker/docker/api/types/seccomp.go | 94 + .../api/types/service_update_response.go | 12 + .../docker/docker/api/types/stats.go | 181 + .../docker/api/types/strslice/strslice.go | 30 + .../docker/docker/api/types/swarm/common.go | 40 + .../docker/docker/api/types/swarm/config.go | 40 + .../docker/api/types/swarm/container.go | 77 + .../docker/docker/api/types/swarm/network.go | 121 + .../docker/docker/api/types/swarm/node.go | 115 + .../docker/docker/api/types/swarm/runtime.go | 27 + .../docker/api/types/swarm/runtime/gen.go | 3 + .../api/types/swarm/runtime/plugin.pb.go | 712 + .../api/types/swarm/runtime/plugin.proto | 20 + .../docker/docker/api/types/swarm/secret.go | 36 + .../docker/docker/api/types/swarm/service.go | 124 + .../docker/docker/api/types/swarm/swarm.go | 227 + .../docker/docker/api/types/swarm/task.go | 192 + .../docker/docker/api/types/types.go | 616 + .../docker/api/types/versions/README.md | 14 + .../docker/api/types/versions/compare.go | 62 + .../docker/docker/api/types/volume.go | 69 + .../docker/docker/contrib/syntax/vim/LICENSE | 22 + .../docker/docker/daemon/logger/adapter.go | 136 + .../docker/docker/daemon/logger/copier.go | 186 + .../docker/docker/daemon/logger/factory.go | 162 + .../daemon/logger/jsonfilelog/jsonfilelog.go | 187 + .../logger/jsonfilelog/jsonlog/jsonlog.go | 25 + .../jsonfilelog/jsonlog/jsonlogbytes.go | 125 + .../jsonfilelog/jsonlog/time_marshalling.go | 20 + .../docker/daemon/logger/jsonfilelog/read.go | 97 + .../docker/docker/daemon/logger/logger.go | 162 + .../daemon/logger/loggerutils/log_tag.go | 31 + .../daemon/logger/loggerutils/logfile.go | 714 + .../docker/docker/daemon/logger/loginfo.go | 145 + .../docker/docker/daemon/logger/metrics.go | 21 + .../docker/docker/daemon/logger/plugin.go | 116 + .../docker/daemon/logger/plugin_unix.go | 23 + .../daemon/logger/plugin_unsupported.go | 12 + .../docker/docker/daemon/logger/proxy.go | 107 + .../docker/docker/daemon/logger/ring.go | 223 + .../daemon/logger/templates/templates.go | 50 + .../docker/docs/static_files/contributors.png | Bin 0 -> 23100 bytes .../github.com/docker/docker/errdefs/defs.go | 69 + .../github.com/docker/docker/errdefs/doc.go | 8 + .../docker/docker/errdefs/helpers.go | 227 + .../docker/docker/errdefs/http_helpers.go | 172 + vendor/github.com/docker/docker/errdefs/is.go | 107 + .../docker/docker/hack/generate-authors.sh | 15 + .../integration-cli/fixtures/https/ca.pem | 1 + .../fixtures/https/client-cert.pem | 1 + .../fixtures/https/client-key.pem | 1 + .../fixtures/https/server-cert.pem | 1 + .../fixtures/https/server-key.pem | 1 + .../docker/pkg/filenotify/filenotify.go | 40 + .../docker/docker/pkg/filenotify/fsnotify.go | 18 + .../docker/docker/pkg/filenotify/poller.go | 213 + .../docker/docker/pkg/ioutils/buffer.go | 51 + .../docker/docker/pkg/ioutils/bytespipe.go | 186 + .../docker/docker/pkg/ioutils/fswriters.go | 162 + .../docker/docker/pkg/ioutils/readers.go | 157 + .../docker/docker/pkg/ioutils/temp_unix.go | 10 + .../docker/docker/pkg/ioutils/temp_windows.go | 16 + .../docker/docker/pkg/ioutils/writeflusher.go | 92 + .../docker/docker/pkg/ioutils/writers.go | 66 + .../docker/pkg/jsonmessage/jsonmessage.go | 283 + .../docker/docker/pkg/longpath/longpath.go | 26 + .../docker/docker/pkg/plugingetter/getter.go | 52 + .../docker/docker/pkg/plugins/client.go | 242 + .../docker/docker/pkg/plugins/discovery.go | 154 + .../docker/pkg/plugins/discovery_unix.go | 5 + .../docker/pkg/plugins/discovery_windows.go | 8 + .../docker/docker/pkg/plugins/errors.go | 33 + .../docker/docker/pkg/plugins/plugins.go | 337 + .../docker/docker/pkg/plugins/plugins_unix.go | 9 + .../docker/pkg/plugins/plugins_windows.go | 7 + .../docker/pkg/plugins/transport/http.go | 36 + .../docker/pkg/plugins/transport/transport.go | 36 + .../docker/docker/pkg/pools/pools.go | 137 + .../docker/docker/pkg/progress/progress.go | 93 + .../docker/pkg/progress/progressreader.go | 66 + .../docker/docker/pkg/pubsub/publisher.go | 124 + .../pkg/streamformatter/streamformatter.go | 159 + .../pkg/streamformatter/streamwriter.go | 47 + .../docker/docker/pkg/stringid/README.md | 1 + .../docker/docker/pkg/stringid/stringid.go | 99 + .../docker/docker/pkg/symlink/LICENSE.APACHE | 191 + .../docker/docker/pkg/symlink/LICENSE.BSD | 27 + .../docker/docker/pkg/tailfile/tailfile.go | 222 + .../docker/docker/pkg/term/ascii.go | 66 + .../docker/docker/pkg/term/proxy.go | 78 + .../github.com/docker/docker/pkg/term/tc.go | 20 + .../github.com/docker/docker/pkg/term/term.go | 124 + .../docker/docker/pkg/term/term_windows.go | 221 + .../docker/docker/pkg/term/termios_bsd.go | 42 + .../docker/docker/pkg/term/termios_linux.go | 39 + .../docker/pkg/term/windows/ansi_reader.go | 263 + .../docker/pkg/term/windows/ansi_writer.go | 64 + .../docker/docker/pkg/term/windows/console.go | 35 + .../docker/docker/pkg/term/windows/windows.go | 33 + .../docker/docker/pkg/term/winsize.go | 20 + .../github.com/docker/go-connections/LICENSE | 191 + .../docker/go-connections/nat/nat.go | 242 + .../docker/go-connections/nat/parse.go | 57 + .../docker/go-connections/nat/sort.go | 96 + .../docker/go-connections/sockets/README.md | 0 .../go-connections/sockets/inmem_socket.go | 81 + .../docker/go-connections/sockets/proxy.go | 51 + .../docker/go-connections/sockets/sockets.go | 38 + .../go-connections/sockets/sockets_unix.go | 35 + .../go-connections/sockets/sockets_windows.go | 27 + .../go-connections/sockets/tcp_socket.go | 22 + .../go-connections/sockets/unix_socket.go | 32 + .../go-connections/tlsconfig/certpool_go17.go | 18 + .../tlsconfig/certpool_other.go | 13 + .../docker/go-connections/tlsconfig/config.go | 254 + .../tlsconfig/config_client_ciphers.go | 17 + .../tlsconfig/config_legacy_client_ciphers.go | 15 + .../docker/go-metrics/CONTRIBUTING.md | 55 + vendor/github.com/docker/go-metrics/LICENSE | 191 + .../github.com/docker/go-metrics/LICENSE.docs | 425 + vendor/github.com/docker/go-metrics/NOTICE | 16 + vendor/github.com/docker/go-metrics/README.md | 91 + .../github.com/docker/go-metrics/counter.go | 52 + vendor/github.com/docker/go-metrics/docs.go | 3 + vendor/github.com/docker/go-metrics/gauge.go | 72 + .../github.com/docker/go-metrics/handler.go | 74 + .../github.com/docker/go-metrics/helpers.go | 10 + .../github.com/docker/go-metrics/namespace.go | 315 + .../github.com/docker/go-metrics/register.go | 15 + vendor/github.com/docker/go-metrics/timer.go | 85 + vendor/github.com/docker/go-metrics/unit.go | 12 + .../docker/go-plugins-helpers/LICENSE | 202 + .../docker/go-plugins-helpers/NOTICE | 19 + .../docker/go-plugins-helpers/sdk/encoder.go | 37 + .../docker/go-plugins-helpers/sdk/handler.go | 88 + .../docker/go-plugins-helpers/sdk/pool.go | 18 + .../sdk/spec_file_generator.go | 58 + .../go-plugins-helpers/sdk/tcp_listener.go | 34 + .../go-plugins-helpers/sdk/unix_listener.go | 35 + .../sdk/unix_listener_nosystemd.go | 10 + .../sdk/unix_listener_systemd.go | 45 + .../sdk/unix_listener_unsupported.go | 16 + .../sdk/windows_listener.go | 70 + .../sdk/windows_listener_unsupported.go | 20 + .../sdk/windows_pipe_config.go | 13 + .../docker/go-units/CONTRIBUTING.md | 67 + vendor/github.com/docker/go-units/LICENSE | 191 + vendor/github.com/docker/go-units/MAINTAINERS | 46 + vendor/github.com/docker/go-units/README.md | 16 + vendor/github.com/docker/go-units/circle.yml | 11 + vendor/github.com/docker/go-units/duration.go | 35 + vendor/github.com/docker/go-units/size.go | 108 + vendor/github.com/docker/go-units/ulimit.go | 123 + .../fsnotify/fsnotify/.editorconfig | 5 + .../github.com/fsnotify/fsnotify/.gitignore | 6 + .../github.com/fsnotify/fsnotify/.travis.yml | 30 + vendor/github.com/fsnotify/fsnotify/AUTHORS | 52 + .../github.com/fsnotify/fsnotify/CHANGELOG.md | 317 + .../fsnotify/fsnotify/CONTRIBUTING.md | 77 + vendor/github.com/fsnotify/fsnotify/LICENSE | 28 + vendor/github.com/fsnotify/fsnotify/README.md | 79 + vendor/github.com/fsnotify/fsnotify/fen.go | 37 + .../github.com/fsnotify/fsnotify/fsnotify.go | 66 + .../github.com/fsnotify/fsnotify/inotify.go | 337 + .../fsnotify/fsnotify/inotify_poller.go | 187 + vendor/github.com/fsnotify/fsnotify/kqueue.go | 521 + .../fsnotify/fsnotify/open_mode_bsd.go | 11 + .../fsnotify/fsnotify/open_mode_darwin.go | 12 + .../github.com/fsnotify/fsnotify/windows.go | 561 + vendor/github.com/gogo/protobuf/io/full.go | 102 + vendor/github.com/gogo/protobuf/io/io.go | 70 + vendor/github.com/gogo/protobuf/io/uint32.go | 138 + vendor/github.com/gogo/protobuf/io/varint.go | 133 + .../gophercloud/gophercloud/.travis.yml | 14 +- .../gophercloud/gophercloud/.zuul.yaml | 28 +- .../gophercloud/gophercloud/auth_options.go | 38 +- .../gophercloud/gophercloud/auth_result.go | 52 + .../github.com/gophercloud/gophercloud/doc.go | 63 +- .../gophercloud/gophercloud/errors.go | 11 + .../github.com/gophercloud/gophercloud/go.mod | 7 + .../github.com/gophercloud/gophercloud/go.sum | 8 + .../gophercloud/openstack/auth_env.go | 47 +- .../gophercloud/openstack/client.go | 29 +- .../compute/v2/extensions/hypervisors/doc.go | 27 +- .../v2/extensions/hypervisors/requests.go | 12 +- .../v2/extensions/hypervisors/results.go | 95 +- .../openstack/compute/v2/flavors/requests.go | 2 +- .../compute/v2/servers/microversions.go | 11 + .../openstack/compute/v2/servers/requests.go | 20 +- .../openstack/identity/v2/tokens/results.go | 15 + .../openstack/identity/v3/tokens/requests.go | 2 +- .../openstack/identity/v3/tokens/results.go | 7 + .../gophercloud/provider_client.go | 144 +- .../gophercloud/gophercloud/service_client.go | 4 + .../gregjones/httpcache/LICENSE.txt | 7 - .../github.com/gregjones/httpcache/README.md | 25 - .../httpcache/diskcache/diskcache.go | 61 - .../gregjones/httpcache/httpcache.go | 551 - vendor/github.com/morikuni/aec/LICENSE | 21 + vendor/github.com/morikuni/aec/README.md | 178 + vendor/github.com/morikuni/aec/aec.go | 137 + vendor/github.com/morikuni/aec/ansi.go | 59 + vendor/github.com/morikuni/aec/builder.go | 388 + vendor/github.com/morikuni/aec/sample.gif | Bin 0 -> 12548 bytes vendor/github.com/morikuni/aec/sgr.go | 202 + .../opencontainers/go-digest/.mailmap | 1 + .../opencontainers/go-digest/.pullapprove.yml | 12 + .../opencontainers/go-digest/.travis.yml | 4 + .../opencontainers/go-digest/CONTRIBUTING.md | 72 + .../opencontainers/go-digest/LICENSE.code | 191 + .../opencontainers/go-digest/LICENSE.docs | 425 + .../opencontainers/go-digest/MAINTAINERS | 9 + .../opencontainers/go-digest/README.md | 104 + .../opencontainers/go-digest/algorithm.go | 192 + .../opencontainers/go-digest/digest.go | 156 + .../opencontainers/go-digest/digester.go | 39 + .../opencontainers/go-digest/doc.go | 56 + .../opencontainers/go-digest/verifiers.go | 45 + .../opencontainers/image-spec/LICENSE | 191 + .../image-spec/specs-go/v1/annotations.go | 56 + .../image-spec/specs-go/v1/config.go | 103 + .../image-spec/specs-go/v1/descriptor.go | 64 + .../image-spec/specs-go/v1/index.go | 29 + .../image-spec/specs-go/v1/layout.go | 28 + .../image-spec/specs-go/v1/manifest.go | 32 + .../image-spec/specs-go/v1/mediatype.go | 48 + .../image-spec/specs-go/version.go | 32 + .../image-spec/specs-go/versioned.go | 23 + .../github.com/peterbourgon/diskv/README.md | 141 - .../peterbourgon/diskv/compression.go | 64 - vendor/github.com/peterbourgon/diskv/diskv.go | 624 - vendor/github.com/peterbourgon/diskv/index.go | 115 - .../prometheus/promhttp/delegator.go | 198 + .../prometheus/promhttp/delegator_1_8.go | 181 + .../prometheus/promhttp/delegator_pre_1_8.go | 44 + .../client_golang/prometheus/promhttp/http.go | 310 + .../prometheus/promhttp/instrument_client.go | 97 + .../promhttp/instrument_client_1_8.go | 144 + .../prometheus/promhttp/instrument_server.go | 447 + .../prometheus/testutil/testutil.go | 187 + .../prometheus/discovery/azure/azure.go | 241 +- .../prometheus/discovery/config/config.go | 26 +- .../prometheus/discovery/consul/consul.go | 33 +- .../prometheus/discovery/dns/dns.go | 83 +- .../prometheus/discovery/ec2/ec2.go | 106 +- .../prometheus/discovery/file/file.go | 13 +- .../prometheus/discovery/gce/gce.go | 119 +- .../discovery/kubernetes/client_metrics.go | 42 +- .../discovery/kubernetes/endpoints.go | 30 +- .../discovery/kubernetes/ingress.go | 33 +- .../discovery/kubernetes/kubernetes.go | 9 +- .../prometheus/discovery/kubernetes/node.go | 31 +- .../prometheus/discovery/kubernetes/pod.go | 24 +- .../discovery/kubernetes/service.go | 32 +- .../prometheus/discovery/marathon/marathon.go | 203 +- .../discovery/openstack/hypervisor.go | 72 +- .../discovery/openstack/instance.go | 81 +- .../discovery/openstack/openstack.go | 75 +- .../prometheus/discovery/refresh/refresh.go | 117 + .../prometheus/discovery/triton/triton.go | 121 +- .../discovery/zookeeper/zookeeper.go | 17 +- .../prometheus/pkg/labels/labels.go | 17 + .../prometheus/pkg/modtimevfs/modtimevfs.go | 67 + .../prometheus/prometheus/pkg/pool/pool.go | 87 + .../prometheus/pkg/relabel/relabel.go | 17 +- .../pkg/textparse/openmetricslex.l.go | 4 +- .../pkg/textparse/openmetricsparse.go | 16 +- .../prometheus/pkg/textparse/promlex.l.go | 4 +- .../prometheus/pkg/textparse/promparse.go | 18 +- .../prometheus/prometheus/promql/ast.go | 6 +- .../prometheus/prometheus/promql/engine.go | 155 +- .../prometheus/prometheus/promql/functions.go | 15 +- .../prometheus/prometheus/promql/lex.go | 348 +- .../prometheus/prometheus/promql/parse.go | 211 +- .../prometheus/prometheus/promql/printer.go | 4 +- .../prometheus/prometheus/promql/test.go | 30 +- .../prometheus/prometheus/promql/value.go | 8 +- .../prometheus/prometheus/relabel/relabel.go | 119 - .../prometheus/template/template.go | 361 + .../prometheus/util/treecache/treecache.go | 3 +- vendor/github.com/shurcooL/httpfs/LICENSE | 21 + .../shurcooL/httpfs/filter/filter.go | 133 + .../shurcooL/httpfs/filter/filters.go | 26 + .../github.com/shurcooL/httpfs/union/union.go | 106 + .../shurcooL/httpfs/vfsutil/file.go | 21 + .../shurcooL/httpfs/vfsutil/vfsutil.go | 39 + .../shurcooL/httpfs/vfsutil/walk.go | 146 + .../httpcache => shurcooL/vfsgen}/.travis.yml | 7 +- .../shurcooL/vfsgen/CONTRIBUTING.md | 10 + vendor/github.com/shurcooL/vfsgen/LICENSE | 21 + vendor/github.com/shurcooL/vfsgen/README.md | 201 + .../shurcooL/vfsgen/commentwriter.go | 45 + vendor/github.com/shurcooL/vfsgen/doc.go | 15 + .../github.com/shurcooL/vfsgen/generator.go | 485 + vendor/github.com/shurcooL/vfsgen/options.go | 45 + .../shurcooL/vfsgen/stringwriter.go | 27 + .../github.com/stretchr/objx/.codeclimate.yml | 13 + vendor/github.com/stretchr/objx/.gitignore | 11 + vendor/github.com/stretchr/objx/.travis.yml | 25 + vendor/github.com/stretchr/objx/Gopkg.lock | 30 + vendor/github.com/stretchr/objx/Gopkg.toml | 8 + vendor/github.com/stretchr/objx/LICENSE | 22 + vendor/github.com/stretchr/objx/README.md | 80 + vendor/github.com/stretchr/objx/Taskfile.yml | 32 + vendor/github.com/stretchr/objx/accessors.go | 148 + vendor/github.com/stretchr/objx/constants.go | 13 + .../github.com/stretchr/objx/conversions.go | 108 + vendor/github.com/stretchr/objx/doc.go | 66 + vendor/github.com/stretchr/objx/map.go | 190 + vendor/github.com/stretchr/objx/mutations.go | 77 + vendor/github.com/stretchr/objx/security.go | 12 + vendor/github.com/stretchr/objx/tests.go | 17 + .../stretchr/objx/type_specific_codegen.go | 2501 + vendor/github.com/stretchr/objx/value.go | 53 + .../github.com/stretchr/testify/mock/doc.go | 44 + .../github.com/stretchr/testify/mock/mock.go | 886 + vendor/github.com/tonistiigi/fifo/.gitignore | 1 + vendor/github.com/tonistiigi/fifo/.travis.yml | 22 + vendor/github.com/tonistiigi/fifo/LICENSE | 201 + vendor/github.com/tonistiigi/fifo/Makefile | 27 + vendor/github.com/tonistiigi/fifo/fifo.go | 236 + .../tonistiigi/fifo/handle_linux.go | 97 + .../tonistiigi/fifo/handle_nolinux.go | 65 + .../tonistiigi/fifo/mkfifo_nosolaris.go | 25 + .../tonistiigi/fifo/mkfifo_solaris.go | 27 + vendor/github.com/tonistiigi/fifo/raw.go | 116 + vendor/github.com/tonistiigi/fifo/readme.md | 44 + .../weaveworks/common/logging/level.go | 5 + .../common/middleware/grpc_logging.go | 12 +- .../weaveworks/common/middleware/logging.go | 5 +- .../weaveworks/common/server/server.go | 16 +- .../golang.org/x/net/internal/socks/client.go | 168 + .../golang.org/x/net/internal/socks/socks.go | 317 + vendor/golang.org/x/net/proxy/direct.go | 18 + vendor/golang.org/x/net/proxy/per_host.go | 140 + vendor/golang.org/x/net/proxy/proxy.go | 139 + vendor/golang.org/x/net/proxy/socks5.go | 36 + .../v1/cloudresourcemanager-api.json | 22 +- .../v1/cloudresourcemanager-gen.go | 292 +- .../api/compute/v1/compute-api.json | 2916 +- .../api/compute/v1/compute-gen.go | 40119 +++++++++------- .../google.golang.org/api/gensupport/media.go | 29 +- .../google.golang.org/api/internal/creds.go | 67 +- .../api/internal/service-account.json | 2 +- .../api/internal/settings.go | 17 +- vendor/google.golang.org/api/option/option.go | 44 + .../api/storage/v1/storage-api.json | 570 +- .../api/storage/v1/storage-gen.go | 1818 +- .../google.golang.org/api/transport/dial.go | 3 - vendor/google.golang.org/api/transport/doc.go | 21 + .../api/transport/grpc/dial.go | 108 +- .../api/transport/http/dial.go | 30 +- vendor/google.golang.org/grpc/.travis.yml | 2 + vendor/google.golang.org/grpc/CONTRIBUTING.md | 58 +- vendor/google.golang.org/grpc/Makefile | 2 +- vendor/google.golang.org/grpc/README.md | 76 +- vendor/google.golang.org/grpc/backoff.go | 2 +- .../grpc/balancer/balancer.go | 72 +- .../grpc/balancer/base/balancer.go | 66 +- .../grpclb/grpc_lb_v1/load_balancer.pb.go | 839 + .../grpc/balancer/grpclb/grpclb.go | 484 + .../grpc/balancer/grpclb/grpclb_config.go | 87 + .../grpc/balancer/grpclb/grpclb_picker.go | 195 + .../balancer/grpclb/grpclb_remote_balancer.go | 355 + .../grpc/balancer/grpclb/grpclb_util.go | 209 + .../grpc/balancer/grpclb/regenerate.sh | 33 + .../grpc/balancer/roundrobin/roundrobin.go | 12 +- .../grpc/balancer_conn_wrappers.go | 43 +- .../grpc/balancer_v1_wrapper.go | 80 +- vendor/google.golang.org/grpc/call.go | 2 +- vendor/google.golang.org/grpc/clientconn.go | 719 +- vendor/google.golang.org/grpc/codes/codes.go | 3 +- .../grpc/connectivity/connectivity.go | 2 +- .../grpc/credentials/alts/alts.go | 330 + .../alts/internal/authinfo/authinfo.go | 87 + .../grpc/credentials/alts/internal/common.go | 69 + .../alts/internal/conn/aeadrekey.go | 131 + .../alts/internal/conn/aes128gcm.go | 105 + .../alts/internal/conn/aes128gcmrekey.go | 116 + .../credentials/alts/internal/conn/common.go | 70 + .../credentials/alts/internal/conn/counter.go | 62 + .../credentials/alts/internal/conn/record.go | 271 + .../credentials/alts/internal/conn/utils.go | 63 + .../alts/internal/handshaker/handshaker.go | 365 + .../internal/handshaker/service/service.go | 54 + .../internal/proto/grpc_gcp/altscontext.pb.go | 151 + .../internal/proto/grpc_gcp/handshaker.pb.go | 1196 + .../grpc_gcp/transport_security_common.pb.go | 178 + .../credentials/alts/internal/regenerate.sh | 35 + .../grpc/credentials/alts/utils.go | 141 + .../grpc/credentials/credentials.go | 18 +- .../grpc/credentials/google/google.go | 125 + .../grpc/credentials/tls13.go | 30 + vendor/google.golang.org/grpc/dialoptions.go | 120 +- .../grpc/encoding/encoding.go | 6 +- vendor/google.golang.org/grpc/go.mod | 14 +- vendor/google.golang.org/grpc/go.sum | 27 +- .../google.golang.org/grpc/grpclog/grpclog.go | 2 +- .../grpc/internal/balancerload/load.go | 46 + .../grpc/internal/binarylog/env_config.go | 6 +- .../grpc/internal/binarylog/method_logger.go | 5 +- .../grpc/internal/channelz/funcs.go | 119 +- .../grpc/internal/envconfig/envconfig.go | 17 +- .../grpc/internal/internal.go | 21 +- .../grpc/internal/syscall/syscall_nonlinux.go | 14 +- .../grpc/internal/transport/handler_server.go | 29 +- .../grpc/internal/transport/http2_client.go | 73 +- .../grpc/internal/transport/http2_server.go | 136 +- .../grpc/internal/transport/http_util.go | 169 +- .../grpc/internal/transport/transport.go | 81 +- .../grpc/keepalive/keepalive.go | 4 +- .../grpc/naming/dns_resolver.go | 6 +- .../google.golang.org/grpc/naming/naming.go | 2 +- .../google.golang.org/grpc/picker_wrapper.go | 31 +- vendor/google.golang.org/grpc/preloader.go | 64 + .../grpc/resolver/dns/dns_resolver.go | 27 +- .../grpc/resolver/passthrough/passthrough.go | 2 +- .../grpc/resolver/resolver.go | 30 + .../grpc/resolver_conn_wrapper.go | 96 +- vendor/google.golang.org/grpc/rpc_util.go | 94 +- vendor/google.golang.org/grpc/server.go | 160 +- .../google.golang.org/grpc/service_config.go | 21 +- vendor/google.golang.org/grpc/stats/stats.go | 5 + vendor/google.golang.org/grpc/stream.go | 106 +- vendor/google.golang.org/grpc/trace.go | 13 + vendor/google.golang.org/grpc/version.go | 2 +- vendor/google.golang.org/grpc/vet.sh | 69 +- .../v1alpha1/generated.proto | 107 - .../admissionregistration/v1alpha1/types.go | 106 - .../v1alpha1/types_swagger_doc_generated.go | 71 - .../api/admissionregistration/v1beta1/doc.go | 3 +- .../v1beta1/generated.pb.go | 1820 +- .../v1beta1/generated.proto | 272 +- .../admissionregistration/v1beta1/types.go | 263 +- .../v1beta1/types_swagger_doc_generated.go | 55 +- .../v1beta1/zz_generated.deepcopy.go | 180 +- vendor/k8s.io/api/apps/v1/doc.go | 1 + vendor/k8s.io/api/apps/v1/types.go | 2 +- .../api/apps/v1/zz_generated.deepcopy.go | 10 +- vendor/k8s.io/api/apps/v1beta1/doc.go | 1 + .../k8s.io/api/apps/v1beta1/generated.proto | 2 +- vendor/k8s.io/api/apps/v1beta1/types.go | 6 +- .../v1beta1/types_swagger_doc_generated.go | 2 +- .../api/apps/v1beta1/zz_generated.deepcopy.go | 6 +- vendor/k8s.io/api/apps/v1beta2/doc.go | 1 + .../k8s.io/api/apps/v1beta2/generated.proto | 28 +- vendor/k8s.io/api/apps/v1beta2/types.go | 32 +- .../v1beta2/types_swagger_doc_generated.go | 28 +- .../api/apps/v1beta2/zz_generated.deepcopy.go | 10 +- .../api/auditregistration/v1alpha1/doc.go | 1 + .../v1alpha1/generated.pb.go | 126 +- .../v1alpha1/generated.proto | 8 +- .../api/auditregistration/v1alpha1/types.go | 8 +- .../v1alpha1/types_swagger_doc_generated.go | 3 +- .../v1alpha1/zz_generated.deepcopy.go | 7 +- vendor/k8s.io/api/authentication/v1/doc.go | 1 + .../api/authentication/v1/generated.proto | 5 +- vendor/k8s.io/api/authentication/v1/types.go | 5 +- .../v1/types_swagger_doc_generated.go | 2 +- .../k8s.io/api/authentication/v1beta1/doc.go | 1 + vendor/k8s.io/api/authorization/v1/doc.go | 1 + .../k8s.io/api/authorization/v1beta1/doc.go | 1 + vendor/k8s.io/api/autoscaling/v1/doc.go | 1 + .../autoscaling/v1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/autoscaling/v2beta1/doc.go | 1 + .../v2beta1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/autoscaling/v2beta2/doc.go | 1 + .../v2beta2/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/batch/v1/doc.go | 1 + .../api/batch/v1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/batch/v1beta1/doc.go | 1 + .../batch/v1beta1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/batch/v2alpha1/doc.go | 1 + .../batch/v2alpha1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/certificates/v1beta1/doc.go | 1 + .../v1beta1/zz_generated.deepcopy.go | 2 +- .../v1alpha1 => coordination/v1}/doc.go | 12 +- .../v1}/generated.pb.go | 552 +- .../api/coordination/v1/generated.proto | 80 + .../v1alpha1 => coordination/v1}/register.go | 16 +- vendor/k8s.io/api/coordination/v1/types.go | 74 + .../v1/types_swagger_doc_generated.go | 63 + .../coordination/v1/zz_generated.deepcopy.go | 124 + vendor/k8s.io/api/coordination/v1beta1/doc.go | 1 + .../v1beta1/zz_generated.deepcopy.go | 2 +- .../api/core/v1/annotation_key_constants.go | 6 + vendor/k8s.io/api/core/v1/doc.go | 1 + vendor/k8s.io/api/core/v1/generated.pb.go | 4309 +- vendor/k8s.io/api/core/v1/generated.proto | 126 +- vendor/k8s.io/api/core/v1/types.go | 152 +- .../core/v1/types_swagger_doc_generated.go | 54 +- .../k8s.io/api/core/v1/well_known_labels.go | 36 + .../api/core/v1/zz_generated.deepcopy.go | 123 +- vendor/k8s.io/api/events/v1beta1/doc.go | 1 + .../k8s.io/api/events/v1beta1/generated.proto | 1 + vendor/k8s.io/api/events/v1beta1/types.go | 1 + .../v1beta1/types_swagger_doc_generated.go | 2 +- .../events/v1beta1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/extensions/v1beta1/doc.go | 1 + .../api/extensions/v1beta1/generated.pb.go | 1034 +- .../api/extensions/v1beta1/generated.proto | 76 +- vendor/k8s.io/api/extensions/v1beta1/types.go | 82 +- .../v1beta1/types_swagger_doc_generated.go | 65 +- .../v1beta1/zz_generated.deepcopy.go | 64 +- vendor/k8s.io/api/networking/v1/doc.go | 1 + .../k8s.io/api/networking/v1/generated.proto | 6 +- vendor/k8s.io/api/networking/v1/types.go | 6 +- .../v1/types_swagger_doc_generated.go | 6 +- .../networking/v1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/networking/v1beta1/doc.go | 22 + .../api/networking/v1beta1/generated.pb.go | 1953 + .../api/networking/v1beta1/generated.proto | 186 + .../k8s.io/api/networking/v1beta1/register.go | 56 + vendor/k8s.io/api/networking/v1beta1/types.go | 192 + .../v1beta1/types_swagger_doc_generated.go | 127 + .../v1beta1/zz_generated.deepcopy.go | 252 + vendor/k8s.io/api/node/v1alpha1/doc.go | 23 + .../k8s.io/api/node/v1alpha1/generated.pb.go | 696 + .../k8s.io/api/node/v1alpha1/generated.proto | 76 + vendor/k8s.io/api/node/v1alpha1/register.go | 52 + vendor/k8s.io/api/node/v1alpha1/types.go | 75 + .../v1alpha1/types_swagger_doc_generated.go | 59 + .../v1alpha1/zz_generated.deepcopy.go | 78 +- vendor/k8s.io/api/node/v1beta1/doc.go | 23 + .../k8s.io/api/node/v1beta1/generated.pb.go | 564 + .../k8s.io/api/node/v1beta1/generated.proto | 66 + vendor/k8s.io/api/node/v1beta1/register.go | 52 + vendor/k8s.io/api/node/v1beta1/types.go | 65 + .../v1beta1/types_swagger_doc_generated.go | 50 + .../api/node/v1beta1/zz_generated.deepcopy.go | 84 + vendor/k8s.io/api/policy/v1beta1/doc.go | 1 + .../k8s.io/api/policy/v1beta1/generated.pb.go | 676 +- .../k8s.io/api/policy/v1beta1/generated.proto | 33 + vendor/k8s.io/api/policy/v1beta1/types.go | 37 +- .../v1beta1/types_swagger_doc_generated.go | 21 + .../policy/v1beta1/zz_generated.deepcopy.go | 56 +- vendor/k8s.io/api/rbac/v1/doc.go | 1 + vendor/k8s.io/api/rbac/v1/generated.proto | 2 + vendor/k8s.io/api/rbac/v1/types.go | 2 + .../api/rbac/v1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/rbac/v1alpha1/doc.go | 1 + .../k8s.io/api/rbac/v1alpha1/generated.proto | 2 + vendor/k8s.io/api/rbac/v1alpha1/types.go | 2 + .../rbac/v1alpha1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/rbac/v1beta1/doc.go | 1 + .../k8s.io/api/rbac/v1beta1/generated.proto | 2 + vendor/k8s.io/api/rbac/v1beta1/types.go | 2 + .../api/rbac/v1beta1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/scheduling/v1/doc.go | 23 + .../k8s.io/api/scheduling/v1/generated.pb.go | 667 + .../k8s.io/api/scheduling/v1/generated.proto | 75 + vendor/k8s.io/api/scheduling/v1/register.go | 55 + vendor/k8s.io/api/scheduling/v1/types.go | 74 + .../v1/types_swagger_doc_generated.go | 53 + .../scheduling/v1/zz_generated.deepcopy.go | 90 + vendor/k8s.io/api/scheduling/v1alpha1/doc.go | 1 + .../api/scheduling/v1alpha1/generated.pb.go | 104 +- .../api/scheduling/v1alpha1/generated.proto | 9 + .../k8s.io/api/scheduling/v1alpha1/types.go | 9 + .../v1alpha1/types_swagger_doc_generated.go | 11 +- .../v1alpha1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/scheduling/v1beta1/doc.go | 1 + .../api/scheduling/v1beta1/generated.pb.go | 104 +- .../api/scheduling/v1beta1/generated.proto | 13 +- vendor/k8s.io/api/scheduling/v1beta1/types.go | 13 +- .../v1beta1/types_swagger_doc_generated.go | 13 +- .../v1beta1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/settings/v1alpha1/doc.go | 1 + .../api/settings/v1alpha1/generated.proto | 2 +- vendor/k8s.io/api/settings/v1alpha1/types.go | 2 +- .../v1alpha1/types_swagger_doc_generated.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 2 +- vendor/k8s.io/api/storage/v1/doc.go | 3 +- vendor/k8s.io/api/storage/v1/generated.pb.go | 192 +- vendor/k8s.io/api/storage/v1/generated.proto | 11 +- vendor/k8s.io/api/storage/v1/types.go | 11 +- .../storage/v1/types_swagger_doc_generated.go | 2 +- .../api/storage/v1/zz_generated.deepcopy.go | 9 +- vendor/k8s.io/api/storage/v1alpha1/doc.go | 3 +- .../api/storage/v1alpha1/generated.pb.go | 159 +- .../api/storage/v1alpha1/generated.proto | 10 + vendor/k8s.io/api/storage/v1alpha1/types.go | 14 +- .../storage/v1alpha1/zz_generated.deepcopy.go | 8 +- vendor/k8s.io/api/storage/v1beta1/doc.go | 1 + .../api/storage/v1beta1/generated.pb.go | 1564 +- .../api/storage/v1beta1/generated.proto | 148 +- vendor/k8s.io/api/storage/v1beta1/register.go | 6 + vendor/k8s.io/api/storage/v1beta1/types.go | 168 +- .../v1beta1/types_swagger_doc_generated.go | 72 +- .../storage/v1beta1/zz_generated.deepcopy.go | 199 +- .../client-go/discovery/cached_discovery.go | 295 - .../client-go/discovery/discovery_client.go | 96 +- .../client-go/discovery/round_tripper.go | 62 - .../k8s.io/client-go/kubernetes/clientset.go | 294 +- .../client-go/kubernetes/scheme/register.go | 14 +- .../v1alpha1/initializerconfiguration.go | 164 - .../coordination/v1/coordination_client.go | 90 + .../kubernetes/typed/coordination/v1/doc.go | 20 + .../coordination/v1/generated_expansion.go | 21 + .../kubernetes/typed/coordination/v1/lease.go | 174 + .../typed/networking/v1beta1/doc.go | 20 + .../networking/v1beta1/generated_expansion.go | 21 + .../typed/networking/v1beta1/ingress.go | 191 + .../networking/v1beta1/networking_client.go | 90 + .../v1alpha1/doc.go | 0 .../v1alpha1/generated_expansion.go | 2 +- .../v1alpha1/node_client.go} | 32 +- .../typed/node/v1alpha1/runtimeclass.go | 164 + .../kubernetes/typed/node/v1beta1/doc.go | 20 + .../typed/node/v1beta1/generated_expansion.go | 21 + .../typed/node/v1beta1/node_client.go | 90 + .../typed/node/v1beta1/runtimeclass.go | 164 + .../kubernetes/typed/scheduling/v1/doc.go | 20 + .../scheduling/v1/generated_expansion.go | 21 + .../typed/scheduling/v1/priorityclass.go | 164 + .../typed/scheduling/v1/scheduling_client.go | 90 + .../typed/storage/v1beta1/csidriver.go | 164 + .../typed/storage/v1beta1/csinode.go | 164 + .../storage/v1beta1/generated_expansion.go | 4 + .../typed/storage/v1beta1/storage_client.go | 10 + .../pkg/apis/clientauthentication/OWNERS | 2 + .../clientauthentication/v1alpha1/types.go | 2 +- .../plugin/pkg/client/auth/exec/exec.go | 15 +- vendor/k8s.io/client-go/rest/OWNERS | 2 + vendor/k8s.io/client-go/rest/config.go | 109 +- vendor/k8s.io/client-go/rest/request.go | 6 +- vendor/k8s.io/client-go/rest/transport.go | 17 +- vendor/k8s.io/client-go/tools/cache/OWNERS | 3 +- .../client-go/tools/cache/controller.go | 72 +- .../client-go/tools/cache/delta_fifo.go | 6 +- .../client-go/tools/cache/expiration_cache.go | 14 +- .../tools/cache/fake_custom_store.go | 2 +- .../k8s.io/client-go/tools/cache/listers.go | 20 + .../k8s.io/client-go/tools/cache/listwatch.go | 14 +- .../k8s.io/client-go/tools/cache/reflector.go | 92 +- .../client-go/tools/cache/shared_informer.go | 2 +- .../tools/cache/thread_safe_store.go | 19 +- .../client-go/tools/clientcmd/api/types.go | 44 + vendor/k8s.io/client-go/tools/metrics/OWNERS | 2 + vendor/k8s.io/client-go/transport/OWNERS | 2 + vendor/k8s.io/client-go/transport/config.go | 20 +- .../client-go/transport/round_trippers.go | 39 +- .../{rest => transport}/token_source.go | 14 +- .../k8s.io/client-go/transport/transport.go | 58 + vendor/k8s.io/client-go/util/cert/OWNERS | 2 + vendor/k8s.io/client-go/util/cert/cert.go | 71 +- vendor/k8s.io/client-go/util/cert/io.go | 95 - vendor/k8s.io/client-go/util/cert/pem.go | 208 - .../client-go/util/flowcontrol/backoff.go | 2 +- vendor/k8s.io/client-go/util/keyutil/OWNERS | 7 + vendor/k8s.io/client-go/util/keyutil/key.go | 323 + vendor/k8s.io/client-go/util/retry/OWNERS | 2 + .../util/workqueue/default_rate_limiters.go | 4 +- .../util/workqueue/delaying_queue.go | 17 +- .../client-go/util/workqueue/metrics.go | 116 +- ...itting_queue.go => rate_limiting_queue.go} | 0 vendor/k8s.io/utils/LICENSE | 202 + .../util => utils}/buffer/ring_growing.go | 0 .../util => utils}/integer/integer.go | 6 + .../utils/third_party/forked/golang/LICENSE | 27 + .../utils/third_party/forked/golang/PATENTS | 22 + vendor/k8s.io/utils/trace/trace.go | 97 + 1128 files changed, 155974 insertions(+), 33084 deletions(-) create mode 100644 .github/pull_request_template.md create mode 100644 .golangci.yml delete mode 100644 .gometalinter.json create mode 100644 CODE_OF_CONDUCT.md create mode 100644 build/Dockerfile create mode 100644 cmd/docker-driver/Dockerfile create mode 100644 cmd/docker-driver/README.md create mode 100644 cmd/docker-driver/config.go create mode 100644 cmd/docker-driver/config.json create mode 100644 cmd/docker-driver/driver.go create mode 100644 cmd/docker-driver/http.go create mode 100644 cmd/docker-driver/loki.go create mode 100644 cmd/docker-driver/main.go create mode 100644 cmd/docker-driver/pipeline-example.yaml create mode 100644 cmd/logcli/output.go create mode 100644 cmd/logcli/query_test.go create mode 100644 cmd/logcli/utils.go create mode 100644 cmd/loki-canary/Dockerfile create mode 100644 cmd/loki-canary/main.go create mode 100644 cmd/loki/Dockerfile.debug create mode 100644 cmd/promtail/Dockerfile.debug create mode 100644 debug/README.md create mode 100644 debug/docker-compose.yaml create mode 100644 docs/canary/README.md create mode 100644 docs/canary/block.png create mode 100644 docs/logentry/processing-log-lines.md create mode 100644 docs/promtail-api.md rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/.gitignore (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/.rspec (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/.rubocop.yml (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/Dockerfile (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/Gemfile (82%) create mode 100644 fluentd/fluent-plugin-grafana-loki/LICENSE rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/README.md (68%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/Rakefile (84%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/bin/console (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/bin/setup (100%) create mode 100644 fluentd/fluent-plugin-grafana-loki/docker/Gemfile rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/conf/fluentd-1.conf (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/conf/fluentd-2.conf (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/conf/fluentd.conf (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/conf/loki.conf (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/conf/systemd.conf (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/docker-compose.yml (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/docker/entrypoint.sh (100%) rename fluentd/{fluent-plugin-loki/fluent-plugin-loki.gemspec => fluent-plugin-grafana-loki/fluent-plugin-grafana-loki.gemspec} (85%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/lib/fluent/plugin/out_loki.rb (91%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/spec/gems/fluent/plugin/data/syslog (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/spec/gems/fluent/plugin/data/syslog2 (100%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/spec/gems/fluent/plugin/loki_output_spec.rb (99%) rename fluentd/{fluent-plugin-loki => fluent-plugin-grafana-loki}/spec/spec_helper.rb (96%) delete mode 100644 fluentd/fluent-plugin-loki/docker/Gemfile create mode 100644 pkg/canary/comparator/comparator.go create mode 100644 pkg/canary/comparator/comparator_test.go create mode 100644 pkg/canary/reader/reader.go create mode 100644 pkg/canary/writer/writer.go create mode 100644 pkg/chunkenc/lazy_chunk.go create mode 100644 pkg/chunkenc/pool.go create mode 100644 pkg/ingester/tailer.go create mode 100644 pkg/ingester/transfer.go create mode 100644 pkg/ingester/transfer_test.go create mode 100644 pkg/logentry/metric/counters.go create mode 100644 pkg/logentry/metric/gauges.go create mode 100644 pkg/logentry/metric/histograms.go create mode 100644 pkg/logentry/metric/metricvec.go create mode 100644 pkg/logentry/stages/extensions.go create mode 100644 pkg/logentry/stages/extensions_test.go create mode 100644 pkg/logentry/stages/json.go create mode 100644 pkg/logentry/stages/json_test.go create mode 100644 pkg/logentry/stages/labels.go create mode 100644 pkg/logentry/stages/labels_test.go create mode 100644 pkg/logentry/stages/match.go create mode 100644 pkg/logentry/stages/match_test.go create mode 100644 pkg/logentry/stages/metrics.go create mode 100644 pkg/logentry/stages/metrics_test.go create mode 100644 pkg/logentry/stages/output.go create mode 100644 pkg/logentry/stages/output_test.go create mode 100644 pkg/logentry/stages/pipeline.go create mode 100644 pkg/logentry/stages/pipeline_test.go create mode 100644 pkg/logentry/stages/regex.go create mode 100644 pkg/logentry/stages/regex_test.go create mode 100644 pkg/logentry/stages/stage.go create mode 100644 pkg/logentry/stages/template.go create mode 100644 pkg/logentry/stages/template_test.go create mode 100644 pkg/logentry/stages/timestamp.go create mode 100644 pkg/logentry/stages/timestamp_test.go create mode 100644 pkg/logentry/stages/util.go create mode 100644 pkg/logentry/stages/util_test.go create mode 100644 pkg/logql/ast.go create mode 100644 pkg/logql/expr.y create mode 100644 pkg/logql/expr.y.go create mode 100644 pkg/logql/parser.go create mode 100644 pkg/logql/parser_test.go delete mode 100644 pkg/parser/labels.go delete mode 100644 pkg/parser/labels.y delete mode 100644 pkg/parser/parser.go delete mode 100644 pkg/parser/parser_test.go create mode 100644 pkg/promtail/client/config.go create mode 100644 pkg/promtail/client/fake/client.go create mode 100644 pkg/promtail/client/multi.go create mode 100644 pkg/promtail/client/multi_test.go create mode 100644 pkg/promtail/scrape/scrape_test.go create mode 100644 pkg/promtail/server/server.go create mode 100644 pkg/promtail/server/template.go create mode 100644 pkg/promtail/server/ui/assets_generate.go create mode 100644 pkg/promtail/server/ui/assets_vfsdata.go create mode 100644 pkg/promtail/server/ui/doc.go create mode 100644 pkg/promtail/server/ui/static/css/promtail.css create mode 100644 pkg/promtail/server/ui/static/css/targets.css create mode 100644 pkg/promtail/server/ui/static/img/favicon.ico create mode 100644 pkg/promtail/server/ui/static/js/targets.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.min.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.min.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.min.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.min.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.min.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.min.css.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.js.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.min.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.min.js.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.js.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.min.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.min.js.map create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap3-typeahead/bootstrap3-typeahead.min.js create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.min.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.eot create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.svg create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.ttf create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff2 create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.eot create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.svg create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.ttf create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff2 create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.eot create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.svg create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.ttf create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff2 create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.eot create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.svg create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.ttf create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff2 create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.css create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.less create mode 100644 pkg/promtail/server/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.min.css create mode 100644 pkg/promtail/server/ui/static/vendor/js/jquery-3.3.1.min.js create mode 100644 pkg/promtail/server/ui/static/vendor/js/jquery.hotkeys.js create mode 100644 pkg/promtail/server/ui/static/vendor/js/jquery.min.js create mode 100644 pkg/promtail/server/ui/static/vendor/js/jquery.selection.js create mode 100644 pkg/promtail/server/ui/static/vendor/js/popper.min.js create mode 100644 pkg/promtail/server/ui/templates/_base.html create mode 100644 pkg/promtail/server/ui/templates/service-discovery.html create mode 100644 pkg/promtail/server/ui/templates/targets.html create mode 100644 pkg/promtail/server/ui/ui.go create mode 100644 pkg/promtail/targets/journaltarget.go create mode 100644 pkg/promtail/targets/journaltarget_test.go create mode 100644 pkg/promtail/targets/journaltargetmanager.go create mode 100644 pkg/promtail/targets/journaltargetmanager_linux.go create mode 100644 pkg/promtail/targets/target.go create mode 100644 pkg/querier/querier_mock_test.go create mode 100644 pkg/querier/querier_test.go delete mode 100644 pkg/querier/store.go create mode 100644 pkg/storage/hack/main.go create mode 100644 pkg/storage/store.go create mode 100644 pkg/storage/store_test.go create mode 100644 pkg/util/conv_test.go create mode 100644 pkg/util/errors.go create mode 100644 pkg/util/flagext/labelset.go create mode 100644 pkg/util/log.go create mode 100644 pkg/util/mock.go create mode 100644 pkg/util/ring.go create mode 100644 production/helm/loki-stack/templates/_helpers.tpl create mode 100644 production/helm/loki-stack/templates/datasources.yaml create mode 100644 production/helm/loki-stack/templates/tests/loki-test-configmap.yaml create mode 100644 production/helm/loki-stack/templates/tests/loki-test-pod.yaml create mode 100644 production/helm/loki/templates/pdb.yaml delete mode 100644 production/helm/loki/templates/pvc.yaml create mode 100644 production/helm/loki/templates/service-headless.yaml rename production/helm/loki/templates/{deployment.yaml => statefulset.yaml} (67%) create mode 100644 production/ksonnet/loki-canary/config.libsonnet create mode 100644 production/ksonnet/loki-canary/jsonnetfile.json create mode 100644 production/ksonnet/loki-canary/loki-canary.libsonnet create mode 100644 production/ksonnet/loki/memcached.libsonnet create mode 100644 tools/dev.values.yaml create mode 100644 tools/helm.yaml create mode 100755 tools/increment_version.sh create mode 100755 tools/release_prepare.sh rename vendor/github.com/{peterbourgon/diskv => Azure/go-ansiterm}/LICENSE (94%) create mode 100644 vendor/github.com/Azure/go-ansiterm/README.md create mode 100644 vendor/github.com/Azure/go-ansiterm/constants.go create mode 100644 vendor/github.com/Azure/go-ansiterm/context.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_entry_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_param_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/event_handler.go create mode 100644 vendor/github.com/Azure/go-ansiterm/ground_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/osc_string_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_actions.go create mode 100644 vendor/github.com/Azure/go-ansiterm/states.go create mode 100644 vendor/github.com/Azure/go-ansiterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/ansi.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/api.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go create mode 100644 vendor/github.com/Microsoft/go-winio/.gitignore create mode 100644 vendor/github.com/Microsoft/go-winio/LICENSE create mode 100644 vendor/github.com/Microsoft/go-winio/README.md create mode 100644 vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE create mode 100644 vendor/github.com/Microsoft/go-winio/backup.go create mode 100644 vendor/github.com/Microsoft/go-winio/ea.go create mode 100644 vendor/github.com/Microsoft/go-winio/file.go create mode 100644 vendor/github.com/Microsoft/go-winio/fileinfo.go create mode 100644 vendor/github.com/Microsoft/go-winio/pipe.go create mode 100644 vendor/github.com/Microsoft/go-winio/privilege.go create mode 100644 vendor/github.com/Microsoft/go-winio/reparse.go create mode 100644 vendor/github.com/Microsoft/go-winio/sd.go create mode 100644 vendor/github.com/Microsoft/go-winio/syscall.go create mode 100644 vendor/github.com/Microsoft/go-winio/zsyscall_windows.go create mode 100644 vendor/github.com/containerd/fifo/.gitignore create mode 100644 vendor/github.com/containerd/fifo/.travis.yml create mode 100644 vendor/github.com/containerd/fifo/LICENSE create mode 100644 vendor/github.com/containerd/fifo/Makefile create mode 100644 vendor/github.com/containerd/fifo/fifo.go create mode 100644 vendor/github.com/containerd/fifo/handle_linux.go create mode 100644 vendor/github.com/containerd/fifo/handle_nolinux.go create mode 100644 vendor/github.com/containerd/fifo/mkfifo_nosolaris.go create mode 100644 vendor/github.com/containerd/fifo/mkfifo_solaris.go create mode 100644 vendor/github.com/containerd/fifo/raw.go create mode 100644 vendor/github.com/containerd/fifo/readme.md create mode 100644 vendor/github.com/coreos/go-systemd/LICENSE create mode 100644 vendor/github.com/coreos/go-systemd/NOTICE create mode 100644 vendor/github.com/coreos/go-systemd/activation/files.go create mode 100644 vendor/github.com/coreos/go-systemd/activation/listeners.go create mode 100644 vendor/github.com/coreos/go-systemd/activation/packetconns.go create mode 100644 vendor/github.com/coreos/go-systemd/sdjournal/functions.go create mode 100644 vendor/github.com/coreos/go-systemd/sdjournal/journal.go create mode 100644 vendor/github.com/coreos/go-systemd/sdjournal/read.go create mode 100644 vendor/github.com/coreos/pkg/LICENSE create mode 100644 vendor/github.com/coreos/pkg/NOTICE create mode 100644 vendor/github.com/coreos/pkg/dlopen/dlopen.go create mode 100644 vendor/github.com/coreos/pkg/dlopen/dlopen_example.go create mode 100644 vendor/github.com/cortexproject/cortex/pkg/chunk/bucket_client.go delete mode 100644 vendor/github.com/cortexproject/cortex/pkg/chunk/cache/diskcache.go rename vendor/github.com/cortexproject/cortex/pkg/{util/wire => chunk/storage}/bytes.go (97%) create mode 100644 vendor/github.com/cortexproject/cortex/pkg/chunk/tags.go create mode 100644 vendor/github.com/cortexproject/cortex/pkg/util/flagext/deprecated.go create mode 100644 vendor/github.com/cortexproject/cortex/pkg/util/labels.go create mode 100644 vendor/github.com/docker/distribution/LICENSE create mode 100644 vendor/github.com/docker/distribution/registry/api/errcode/errors.go create mode 100644 vendor/github.com/docker/distribution/registry/api/errcode/handler.go create mode 100644 vendor/github.com/docker/distribution/registry/api/errcode/register.go create mode 100644 vendor/github.com/docker/docker/AUTHORS create mode 100644 vendor/github.com/docker/docker/LICENSE create mode 100644 vendor/github.com/docker/docker/NOTICE create mode 100644 vendor/github.com/docker/docker/api/types/auth.go create mode 100644 vendor/github.com/docker/docker/api/types/backend/backend.go create mode 100644 vendor/github.com/docker/docker/api/types/backend/build.go create mode 100644 vendor/github.com/docker/docker/api/types/blkiodev/blkio.go create mode 100644 vendor/github.com/docker/docker/api/types/client.go create mode 100644 vendor/github.com/docker/docker/api/types/configs.go create mode 100644 vendor/github.com/docker/docker/api/types/container/config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_changes.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_create.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_top.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_update.go create mode 100644 vendor/github.com/docker/docker/api/types/container/container_wait.go create mode 100644 vendor/github.com/docker/docker/api/types/container/host_config.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go create mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go create mode 100644 vendor/github.com/docker/docker/api/types/container/waitcondition.go create mode 100644 vendor/github.com/docker/docker/api/types/error_response.go create mode 100644 vendor/github.com/docker/docker/api/types/filters/parse.go create mode 100644 vendor/github.com/docker/docker/api/types/graph_driver_data.go create mode 100644 vendor/github.com/docker/docker/api/types/id_response.go create mode 100644 vendor/github.com/docker/docker/api/types/image_delete_response_item.go create mode 100644 vendor/github.com/docker/docker/api/types/image_summary.go create mode 100644 vendor/github.com/docker/docker/api/types/mount/mount.go create mode 100644 vendor/github.com/docker/docker/api/types/network/network.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_device.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_env.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_interface_type.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_mount.go create mode 100644 vendor/github.com/docker/docker/api/types/plugin_responses.go create mode 100644 vendor/github.com/docker/docker/api/types/plugins/logdriver/entry.pb.go create mode 100644 vendor/github.com/docker/docker/api/types/plugins/logdriver/entry.proto create mode 100644 vendor/github.com/docker/docker/api/types/plugins/logdriver/gen.go create mode 100644 vendor/github.com/docker/docker/api/types/plugins/logdriver/io.go create mode 100644 vendor/github.com/docker/docker/api/types/port.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/authenticate.go create mode 100644 vendor/github.com/docker/docker/api/types/registry/registry.go create mode 100644 vendor/github.com/docker/docker/api/types/seccomp.go create mode 100644 vendor/github.com/docker/docker/api/types/service_update_response.go create mode 100644 vendor/github.com/docker/docker/api/types/stats.go create mode 100644 vendor/github.com/docker/docker/api/types/strslice/strslice.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/common.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/config.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/container.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/network.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/node.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/gen.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.pb.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/plugin.proto create mode 100644 vendor/github.com/docker/docker/api/types/swarm/secret.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/service.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/swarm.go create mode 100644 vendor/github.com/docker/docker/api/types/swarm/task.go create mode 100644 vendor/github.com/docker/docker/api/types/types.go create mode 100644 vendor/github.com/docker/docker/api/types/versions/README.md create mode 100644 vendor/github.com/docker/docker/api/types/versions/compare.go create mode 100644 vendor/github.com/docker/docker/api/types/volume.go create mode 100644 vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE create mode 100644 vendor/github.com/docker/docker/daemon/logger/adapter.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/copier.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/factory.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/jsonfilelog/jsonfilelog.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog/jsonlog.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog/jsonlogbytes.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog/time_marshalling.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/jsonfilelog/read.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/logger.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/loggerutils/log_tag.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/loggerutils/logfile.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/loginfo.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/metrics.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/plugin.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/plugin_unix.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/plugin_unsupported.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/proxy.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/ring.go create mode 100644 vendor/github.com/docker/docker/daemon/logger/templates/templates.go create mode 100644 vendor/github.com/docker/docker/docs/static_files/contributors.png create mode 100644 vendor/github.com/docker/docker/errdefs/defs.go create mode 100644 vendor/github.com/docker/docker/errdefs/doc.go create mode 100644 vendor/github.com/docker/docker/errdefs/helpers.go create mode 100644 vendor/github.com/docker/docker/errdefs/http_helpers.go create mode 100644 vendor/github.com/docker/docker/errdefs/is.go create mode 100755 vendor/github.com/docker/docker/hack/generate-authors.sh create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/ca.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/client-cert.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/client-key.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/server-cert.pem create mode 120000 vendor/github.com/docker/docker/integration-cli/fixtures/https/server-key.pem create mode 100644 vendor/github.com/docker/docker/pkg/filenotify/filenotify.go create mode 100644 vendor/github.com/docker/docker/pkg/filenotify/fsnotify.go create mode 100644 vendor/github.com/docker/docker/pkg/filenotify/poller.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/buffer.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/fswriters.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/readers.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go create mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writers.go create mode 100644 vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go create mode 100644 vendor/github.com/docker/docker/pkg/longpath/longpath.go create mode 100644 vendor/github.com/docker/docker/pkg/plugingetter/getter.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/client.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/discovery.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/discovery_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/discovery_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/errors.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/plugins.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/plugins_unix.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/plugins_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/transport/http.go create mode 100644 vendor/github.com/docker/docker/pkg/plugins/transport/transport.go create mode 100644 vendor/github.com/docker/docker/pkg/pools/pools.go create mode 100644 vendor/github.com/docker/docker/pkg/progress/progress.go create mode 100644 vendor/github.com/docker/docker/pkg/progress/progressreader.go create mode 100644 vendor/github.com/docker/docker/pkg/pubsub/publisher.go create mode 100644 vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go create mode 100644 vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go create mode 100644 vendor/github.com/docker/docker/pkg/stringid/README.md create mode 100644 vendor/github.com/docker/docker/pkg/stringid/stringid.go create mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE create mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD create mode 100644 vendor/github.com/docker/docker/pkg/tailfile/tailfile.go create mode 100644 vendor/github.com/docker/docker/pkg/term/ascii.go create mode 100644 vendor/github.com/docker/docker/pkg/term/proxy.go create mode 100644 vendor/github.com/docker/docker/pkg/term/tc.go create mode 100644 vendor/github.com/docker/docker/pkg/term/term.go create mode 100644 vendor/github.com/docker/docker/pkg/term/term_windows.go create mode 100644 vendor/github.com/docker/docker/pkg/term/termios_bsd.go create mode 100644 vendor/github.com/docker/docker/pkg/term/termios_linux.go create mode 100644 vendor/github.com/docker/docker/pkg/term/windows/ansi_reader.go create mode 100644 vendor/github.com/docker/docker/pkg/term/windows/ansi_writer.go create mode 100644 vendor/github.com/docker/docker/pkg/term/windows/console.go create mode 100644 vendor/github.com/docker/docker/pkg/term/windows/windows.go create mode 100644 vendor/github.com/docker/docker/pkg/term/winsize.go create mode 100644 vendor/github.com/docker/go-connections/LICENSE create mode 100644 vendor/github.com/docker/go-connections/nat/nat.go create mode 100644 vendor/github.com/docker/go-connections/nat/parse.go create mode 100644 vendor/github.com/docker/go-connections/nat/sort.go create mode 100644 vendor/github.com/docker/go-connections/sockets/README.md create mode 100644 vendor/github.com/docker/go-connections/sockets/inmem_socket.go create mode 100644 vendor/github.com/docker/go-connections/sockets/proxy.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets_unix.go create mode 100644 vendor/github.com/docker/go-connections/sockets/sockets_windows.go create mode 100644 vendor/github.com/docker/go-connections/sockets/tcp_socket.go create mode 100644 vendor/github.com/docker/go-connections/sockets/unix_socket.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go create mode 100644 vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go create mode 100644 vendor/github.com/docker/go-metrics/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/go-metrics/LICENSE create mode 100644 vendor/github.com/docker/go-metrics/LICENSE.docs create mode 100644 vendor/github.com/docker/go-metrics/NOTICE create mode 100644 vendor/github.com/docker/go-metrics/README.md create mode 100644 vendor/github.com/docker/go-metrics/counter.go create mode 100644 vendor/github.com/docker/go-metrics/docs.go create mode 100644 vendor/github.com/docker/go-metrics/gauge.go create mode 100644 vendor/github.com/docker/go-metrics/handler.go create mode 100644 vendor/github.com/docker/go-metrics/helpers.go create mode 100644 vendor/github.com/docker/go-metrics/namespace.go create mode 100644 vendor/github.com/docker/go-metrics/register.go create mode 100644 vendor/github.com/docker/go-metrics/timer.go create mode 100644 vendor/github.com/docker/go-metrics/unit.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/LICENSE create mode 100644 vendor/github.com/docker/go-plugins-helpers/NOTICE create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/encoder.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/handler.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/pool.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/spec_file_generator.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/tcp_listener.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/unix_listener.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/unix_listener_nosystemd.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/unix_listener_systemd.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/unix_listener_unsupported.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/windows_listener.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/windows_listener_unsupported.go create mode 100644 vendor/github.com/docker/go-plugins-helpers/sdk/windows_pipe_config.go create mode 100644 vendor/github.com/docker/go-units/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/go-units/LICENSE create mode 100644 vendor/github.com/docker/go-units/MAINTAINERS create mode 100644 vendor/github.com/docker/go-units/README.md create mode 100644 vendor/github.com/docker/go-units/circle.yml create mode 100644 vendor/github.com/docker/go-units/duration.go create mode 100644 vendor/github.com/docker/go-units/size.go create mode 100644 vendor/github.com/docker/go-units/ulimit.go create mode 100644 vendor/github.com/fsnotify/fsnotify/.editorconfig create mode 100644 vendor/github.com/fsnotify/fsnotify/.gitignore create mode 100644 vendor/github.com/fsnotify/fsnotify/.travis.yml create mode 100644 vendor/github.com/fsnotify/fsnotify/AUTHORS create mode 100644 vendor/github.com/fsnotify/fsnotify/CHANGELOG.md create mode 100644 vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md create mode 100644 vendor/github.com/fsnotify/fsnotify/LICENSE create mode 100644 vendor/github.com/fsnotify/fsnotify/README.md create mode 100644 vendor/github.com/fsnotify/fsnotify/fen.go create mode 100644 vendor/github.com/fsnotify/fsnotify/fsnotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/inotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/inotify_poller.go create mode 100644 vendor/github.com/fsnotify/fsnotify/kqueue.go create mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go create mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go create mode 100644 vendor/github.com/fsnotify/fsnotify/windows.go create mode 100644 vendor/github.com/gogo/protobuf/io/full.go create mode 100644 vendor/github.com/gogo/protobuf/io/io.go create mode 100644 vendor/github.com/gogo/protobuf/io/uint32.go create mode 100644 vendor/github.com/gogo/protobuf/io/varint.go create mode 100644 vendor/github.com/gophercloud/gophercloud/auth_result.go create mode 100644 vendor/github.com/gophercloud/gophercloud/go.mod create mode 100644 vendor/github.com/gophercloud/gophercloud/go.sum create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/microversions.go delete mode 100644 vendor/github.com/gregjones/httpcache/LICENSE.txt delete mode 100644 vendor/github.com/gregjones/httpcache/README.md delete mode 100644 vendor/github.com/gregjones/httpcache/diskcache/diskcache.go delete mode 100644 vendor/github.com/gregjones/httpcache/httpcache.go create mode 100644 vendor/github.com/morikuni/aec/LICENSE create mode 100644 vendor/github.com/morikuni/aec/README.md create mode 100644 vendor/github.com/morikuni/aec/aec.go create mode 100644 vendor/github.com/morikuni/aec/ansi.go create mode 100644 vendor/github.com/morikuni/aec/builder.go create mode 100644 vendor/github.com/morikuni/aec/sample.gif create mode 100644 vendor/github.com/morikuni/aec/sgr.go create mode 100644 vendor/github.com/opencontainers/go-digest/.mailmap create mode 100644 vendor/github.com/opencontainers/go-digest/.pullapprove.yml create mode 100644 vendor/github.com/opencontainers/go-digest/.travis.yml create mode 100644 vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE.code create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE.docs create mode 100644 vendor/github.com/opencontainers/go-digest/MAINTAINERS create mode 100644 vendor/github.com/opencontainers/go-digest/README.md create mode 100644 vendor/github.com/opencontainers/go-digest/algorithm.go create mode 100644 vendor/github.com/opencontainers/go-digest/digest.go create mode 100644 vendor/github.com/opencontainers/go-digest/digester.go create mode 100644 vendor/github.com/opencontainers/go-digest/doc.go create mode 100644 vendor/github.com/opencontainers/go-digest/verifiers.go create mode 100644 vendor/github.com/opencontainers/image-spec/LICENSE create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/version.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/versioned.go delete mode 100644 vendor/github.com/peterbourgon/diskv/README.md delete mode 100644 vendor/github.com/peterbourgon/diskv/compression.go delete mode 100644 vendor/github.com/peterbourgon/diskv/diskv.go delete mode 100644 vendor/github.com/peterbourgon/diskv/index.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/testutil.go create mode 100644 vendor/github.com/prometheus/prometheus/discovery/refresh/refresh.go create mode 100644 vendor/github.com/prometheus/prometheus/pkg/modtimevfs/modtimevfs.go create mode 100644 vendor/github.com/prometheus/prometheus/pkg/pool/pool.go delete mode 100644 vendor/github.com/prometheus/prometheus/relabel/relabel.go create mode 100644 vendor/github.com/prometheus/prometheus/template/template.go create mode 100644 vendor/github.com/shurcooL/httpfs/LICENSE create mode 100644 vendor/github.com/shurcooL/httpfs/filter/filter.go create mode 100644 vendor/github.com/shurcooL/httpfs/filter/filters.go create mode 100644 vendor/github.com/shurcooL/httpfs/union/union.go create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/file.go create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/vfsutil.go create mode 100644 vendor/github.com/shurcooL/httpfs/vfsutil/walk.go rename vendor/github.com/{gregjones/httpcache => shurcooL/vfsgen}/.travis.yml (81%) create mode 100644 vendor/github.com/shurcooL/vfsgen/CONTRIBUTING.md create mode 100644 vendor/github.com/shurcooL/vfsgen/LICENSE create mode 100644 vendor/github.com/shurcooL/vfsgen/README.md create mode 100644 vendor/github.com/shurcooL/vfsgen/commentwriter.go create mode 100644 vendor/github.com/shurcooL/vfsgen/doc.go create mode 100644 vendor/github.com/shurcooL/vfsgen/generator.go create mode 100644 vendor/github.com/shurcooL/vfsgen/options.go create mode 100644 vendor/github.com/shurcooL/vfsgen/stringwriter.go create mode 100644 vendor/github.com/stretchr/objx/.codeclimate.yml create mode 100644 vendor/github.com/stretchr/objx/.gitignore create mode 100644 vendor/github.com/stretchr/objx/.travis.yml create mode 100644 vendor/github.com/stretchr/objx/Gopkg.lock create mode 100644 vendor/github.com/stretchr/objx/Gopkg.toml create mode 100644 vendor/github.com/stretchr/objx/LICENSE create mode 100644 vendor/github.com/stretchr/objx/README.md create mode 100644 vendor/github.com/stretchr/objx/Taskfile.yml create mode 100644 vendor/github.com/stretchr/objx/accessors.go create mode 100644 vendor/github.com/stretchr/objx/constants.go create mode 100644 vendor/github.com/stretchr/objx/conversions.go create mode 100644 vendor/github.com/stretchr/objx/doc.go create mode 100644 vendor/github.com/stretchr/objx/map.go create mode 100644 vendor/github.com/stretchr/objx/mutations.go create mode 100644 vendor/github.com/stretchr/objx/security.go create mode 100644 vendor/github.com/stretchr/objx/tests.go create mode 100644 vendor/github.com/stretchr/objx/type_specific_codegen.go create mode 100644 vendor/github.com/stretchr/objx/value.go create mode 100644 vendor/github.com/stretchr/testify/mock/doc.go create mode 100644 vendor/github.com/stretchr/testify/mock/mock.go create mode 100644 vendor/github.com/tonistiigi/fifo/.gitignore create mode 100644 vendor/github.com/tonistiigi/fifo/.travis.yml create mode 100644 vendor/github.com/tonistiigi/fifo/LICENSE create mode 100644 vendor/github.com/tonistiigi/fifo/Makefile create mode 100644 vendor/github.com/tonistiigi/fifo/fifo.go create mode 100644 vendor/github.com/tonistiigi/fifo/handle_linux.go create mode 100644 vendor/github.com/tonistiigi/fifo/handle_nolinux.go create mode 100644 vendor/github.com/tonistiigi/fifo/mkfifo_nosolaris.go create mode 100644 vendor/github.com/tonistiigi/fifo/mkfifo_solaris.go create mode 100644 vendor/github.com/tonistiigi/fifo/raw.go create mode 100644 vendor/github.com/tonistiigi/fifo/readme.md create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/google.golang.org/api/transport/doc.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_config.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go create mode 100755 vendor/google.golang.org/grpc/balancer/grpclb/regenerate.sh create mode 100644 vendor/google.golang.org/grpc/credentials/alts/alts.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/common.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go create mode 100755 vendor/google.golang.org/grpc/credentials/alts/internal/regenerate.sh create mode 100644 vendor/google.golang.org/grpc/credentials/alts/utils.go create mode 100644 vendor/google.golang.org/grpc/credentials/google/google.go create mode 100644 vendor/google.golang.org/grpc/credentials/tls13.go create mode 100644 vendor/google.golang.org/grpc/internal/balancerload/load.go create mode 100644 vendor/google.golang.org/grpc/preloader.go delete mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto delete mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/types.go delete mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go rename vendor/k8s.io/api/{admissionregistration/v1alpha1 => coordination/v1}/doc.go (57%) rename vendor/k8s.io/api/{admissionregistration/v1alpha1 => coordination/v1}/generated.pb.go (51%) create mode 100644 vendor/k8s.io/api/coordination/v1/generated.proto rename vendor/k8s.io/api/{admissionregistration/v1alpha1 => coordination/v1}/register.go (86%) create mode 100644 vendor/k8s.io/api/coordination/v1/types.go create mode 100644 vendor/k8s.io/api/coordination/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/coordination/v1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/core/v1/well_known_labels.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/networking/v1beta1/register.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/types.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/node/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/types_swagger_doc_generated.go rename vendor/k8s.io/api/{admissionregistration => node}/v1alpha1/zz_generated.deepcopy.go (51%) create mode 100644 vendor/k8s.io/api/node/v1beta1/doc.go create mode 100644 vendor/k8s.io/api/node/v1beta1/generated.pb.go create mode 100644 vendor/k8s.io/api/node/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/node/v1beta1/register.go create mode 100644 vendor/k8s.io/api/node/v1beta1/types.go create mode 100644 vendor/k8s.io/api/node/v1beta1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/node/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/scheduling/v1/doc.go create mode 100644 vendor/k8s.io/api/scheduling/v1/generated.pb.go create mode 100644 vendor/k8s.io/api/scheduling/v1/generated.proto create mode 100644 vendor/k8s.io/api/scheduling/v1/register.go create mode 100644 vendor/k8s.io/api/scheduling/v1/types.go create mode 100644 vendor/k8s.io/api/scheduling/v1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/scheduling/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/client-go/discovery/cached_discovery.go delete mode 100644 vendor/k8s.io/client-go/discovery/round_tripper.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/initializerconfiguration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/coordination_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1/lease.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/ingress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/networking_client.go rename vendor/k8s.io/client-go/kubernetes/typed/{admissionregistration => node}/v1alpha1/doc.go (100%) rename vendor/k8s.io/client-go/kubernetes/typed/{admissionregistration => node}/v1alpha1/generated_expansion.go (92%) rename vendor/k8s.io/client-go/kubernetes/typed/{admissionregistration/v1alpha1/admissionregistration_client.go => node/v1alpha1/node_client.go} (58%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1alpha1/runtimeclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/node_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/node/v1beta1/runtimeclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/priorityclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1/scheduling_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csidriver.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csinode.go mode change 100755 => 100644 vendor/k8s.io/client-go/rest/OWNERS mode change 100755 => 100644 vendor/k8s.io/client-go/tools/cache/OWNERS mode change 100755 => 100644 vendor/k8s.io/client-go/tools/metrics/OWNERS mode change 100755 => 100644 vendor/k8s.io/client-go/transport/OWNERS rename vendor/k8s.io/client-go/{rest => transport}/token_source.go (87%) create mode 100644 vendor/k8s.io/client-go/util/keyutil/OWNERS create mode 100644 vendor/k8s.io/client-go/util/keyutil/key.go mode change 100755 => 100644 vendor/k8s.io/client-go/util/retry/OWNERS rename vendor/k8s.io/client-go/util/workqueue/{rate_limitting_queue.go => rate_limiting_queue.go} (100%) create mode 100644 vendor/k8s.io/utils/LICENSE rename vendor/k8s.io/{client-go/util => utils}/buffer/ring_growing.go (100%) rename vendor/k8s.io/{client-go/util => utils}/integer/integer.go (81%) create mode 100644 vendor/k8s.io/utils/third_party/forked/golang/LICENSE create mode 100644 vendor/k8s.io/utils/third_party/forked/golang/PATENTS create mode 100644 vendor/k8s.io/utils/trace/trace.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 6a0d1dc4f3183..5e1a8bb638c24 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,11 +5,13 @@ workflows: test-build-deploy: jobs: - test + - test-helm - build - lint - publish: requires: - test + - test-helm - build - lint filters: @@ -18,6 +20,7 @@ workflows: - publish-master: requires: - test + - test-helm - build - lint filters: @@ -26,6 +29,7 @@ workflows: - publish-helm: requires: - test + - test-helm - build - lint filters: @@ -41,7 +45,7 @@ workflows: # https://circleci.com/blog/circleci-hacks-reuse-yaml-in-your-circleci-config-with-yaml/ defaults: &defaults docker: - - image: grafana/loki-build-image:0.1.0 + - image: grafana/loki-build-image:0.3.0 working_directory: /go/src/github.com/grafana/loki jobs: @@ -53,8 +57,7 @@ jobs: - run: name: Run Unit Tests command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false test + make test lint: <<: *defaults @@ -64,13 +67,11 @@ jobs: - run: name: Lint command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false lint + make lint - run: name: Check Generated Fies command: | - touch loki-build-image/.uptodate && make BUILD_IN_CONTAINER=false check-generated-files build: @@ -79,23 +80,33 @@ jobs: - checkout - setup_remote_docker + - run: + name: Promtail cross platform + command: | + make GOOS=linux BUILD_IN_CONTAINER=false promtail + rm cmd/promtail/promtail + make GOOS=windows BUILD_IN_CONTAINER=false promtail + - run: name: Build Images command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false + make images - run: name: Save Images command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false save-images + make save-images - save_cache: key: v1-loki-{{ .Branch }}-{{ .Revision }} paths: - images/ + - save_cache: + key: v1-loki-plugin-{{ .Branch }}-{{ .Revision }} + paths: + - cmd/docker-driver/docker-driver + publish: <<: *defaults steps: @@ -104,12 +115,13 @@ jobs: - restore_cache: key: v1-loki-{{ .Branch }}-{{ .Revision }} + - restore_cache: + key: v1-loki-plugin-{{ .Branch }}-{{ .Revision }} - run: name: Load Images command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false load-images + make load-images - run: name: Push Images @@ -119,6 +131,14 @@ jobs: make push-images fi + - run: + name: Push Docker Plugin + command: | + if [ -n "$DOCKER_USER" ]; then + docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" && + make BUILD_IN_CONTAINER=false docker-driver-push + fi + publish-master: <<: *defaults steps: @@ -127,12 +147,13 @@ jobs: - restore_cache: key: v1-loki-{{ .Branch }}-{{ .Revision }} + - restore_cache: + key: v1-loki-plugin-{{ .Branch }}-{{ .Revision }} - run: name: Load Images command: | - touch loki-build-image/.uptodate && - make BUILD_IN_CONTAINER=false load-images + make load-images - run: name: Push Images @@ -140,6 +161,47 @@ jobs: docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" && make push-latest + - run: + name: Push Docker Plugin + command: | + if [ -n "$DOCKER_USER" ]; then + docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" && + PLUGIN_TAG=master make BUILD_IN_CONTAINER=false docker-driver-push && PLUGIN_TAG=latest make BUILD_IN_CONTAINER=false docker-driver-push + fi + + test-helm: + environment: + CT_VERSION: 2.3.3 + machine: + image: ubuntu-1604:201903-01 + steps: + - checkout + - run: + name: Install k3s + command: | + curl -sfL https://get.k3s.io | sh - + sudo chmod 755 /etc/rancher/k3s/k3s.yaml + mkdir -p ~/.kube + cp /etc/rancher/k3s/k3s.yaml ~/.kube/config + - run: + name: Install Helm + command: | + curl -L https://git.io/get_helm.sh | bash + kubectl apply -f tools/helm.yaml + helm init --service-account helm --wait + - run: + name: Install Chart Testing tool + command: | + pip install yamale yamllint + curl -Lo ct.tgz https://github.com/helm/chart-testing/releases/download/v${CT_VERSION}/chart-testing_${CT_VERSION}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xvf ct.tgz + sudo mv /usr/local/bin/etc /etc/ct/ + - run: + name: Run Chart Tests + command: | + ct lint --chart-dirs=production/helm --check-version-increment=false --validate-maintainers=false + ct install --build-id=${CIRCLE_BUILD_NUM} --charts production/helm/loki-stack + publish-helm: <<: *defaults steps: @@ -159,3 +221,24 @@ jobs: --data "{\"build_parameters\": {\"CIRCLE_JOB\": \"deploy\", \"IMAGE_NAMES\": \"$(make images)\"}}" \ --request POST \ https://circleci.com/api/v1.1/project/github/raintank/deployment_tools/tree/master?circle-token=$CIRCLE_TOKEN + + release: + <<: *defaults + steps: + - checkout + - setup_remote_docker + - restore_cache: + key: v1-loki-{{ .Branch }}-{{ .Revision }} + - run: + name: Load Images + command: | + touch loki-build-image/.uptodate && + make BUILD_IN_CONTAINER=false load-images + - run: + name: "Print Tag" + command: echo ${CIRCLE_TAG} + - run: + name: "Release" + command: | + docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" && + make VERSION=${CIRCLE_TAG} release-perform diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000000..e8e08c0eb805a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ + + +**What this PR does / why we need it**: + +**Which issue(s) this PR fixes**: +Fixes # + +**Special notes for your reviewer**: + +**Checklist** +- [ ] Documentation added +- [ ] Tests updated + diff --git a/.gitignore b/.gitignore index dec47fd3a9606..a9a40e0fb4fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .uptodate +.uptodate-debug .pkg .cache *.output @@ -7,6 +8,13 @@ requirements.lock mixin/vendor/ cmd/loki/loki cmd/promtail/promtail +cmd/loki/loki-debug +cmd/promtail/promtail-debug +cmd/docker-driver/docker-driver +cmd/loki-canary/loki-canary /loki /promtail /logcli +/loki-canary +dlv +rootfs/ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000000..2583383fdbcd2 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,66 @@ +# This file contains all available configuration options +# with their default values. + +# options for analysis running +run: + # default concurrency is a available CPU number + concurrency: 2 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 5m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + + # include test files or not, default is true + tests: true + + # list of build tags, all linters use it. Default is empty list. + build-tags: + + # which dirs to skip: they won't be analyzed; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but next dirs are always skipped independently + # from this option's value: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs: + # which files to skip: they will be analyzed, but issues from them + # won't be reported. Default value is empty list, but there is + # no need to include all autogenerated files, we confidently recognize + # autogenerated files. If it's not please let us know. + skip-files: +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + +linters: + enable: + - deadcode + - errcheck + - goconst + - gofmt + - goimports + - golint + - gosimple + - ineffassign + - megacheck + - misspell + - structcheck + - unconvert + - unparam + - varcheck + - govet + - unused # new from here. + - interfacer + - typecheck + +issues: + exclude: + - Error return value of .*log\.Logger\)\.Log\x60 is not checked \ No newline at end of file diff --git a/.gometalinter.json b/.gometalinter.json deleted file mode 100644 index ed3fda665df43..0000000000000 --- a/.gometalinter.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "Vendor": true, - "Deadline": "5m", - "Concurrency": 2, - "Linters": { - "gofmt": {"Command": "gofmt -l -s -w"}, - "goimports": {"Command": "goimports -l -w"} - }, - "Exclude": [ - "\\.pb\\.go", - "method Seek.*should have signature", - "error return value not checked \\(level\\.", - "\"err\" shadows declaration" - ], - - "Enable": [ - "deadcode", - "errcheck", - "goconst", - "gofmt", - "goimports", - "golint", - "gosimple", - "gotypex", - "ineffassign", - "megacheck", - "misspell", - "structcheck", - "unconvert", - "unparam", - "varcheck", - "vet", - "vetshadow" - ] -} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..c6bffe79b060f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@grafana.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 929b3bc7c5dce..9728341d22b1f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,3 +18,8 @@ $ git remote add ``` Notice: `go get` return `package github.com/grafana/loki: no Go files in /go/src/github.com/grafana/loki` is normal. + + +## Contribute to helm + +Please follow [doc](./production/helm/README.md). diff --git a/Gopkg.lock b/Gopkg.lock index 250b4fa3606a3..67c3f93e03787 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -43,6 +43,17 @@ revision = "a1a2da0aba294fe51ba47119e652ff2f08a78afb" version = "v26.3.0" +[[projects]] + branch = "master" + digest = "1:6da51e5ec493ad2b44cb04129e2d0a068c8fb9bd6cb5739d199573558696bb94" + name = "github.com/Azure/go-ansiterm" + packages = [ + ".", + "winterm", + ] + pruneopts = "UT" + revision = "d6e3b3328b783f23731bc4d058875b0371ff8109" + [[projects]] digest = "1:ae0afbb4ba38fc78943a738a1d853294a9591d9c7dd69594d641b7649535d518" name = "github.com/Azure/go-autorest" @@ -60,6 +71,14 @@ revision = "134ac34d5a96fc72758c0f157f38f87cbdb3f532" version = "v11.5.1" +[[projects]] + digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892" + name = "github.com/Microsoft/go-winio" + packages = ["."] + pruneopts = "UT" + revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8" + version = "v0.4.12" + [[projects]] branch = "master" digest = "1:315c5f2f60c76d89b871c73f9bd5fe689cad96597afd50fb9992228ef80bdd34" @@ -187,7 +206,34 @@ [[projects]] branch = "master" - digest = "1:5750dfa5a8160b51a01c02d6d7841b50fe7d2d97344c200fc4cdc3c46b3953f8" + digest = "1:9ab2182297ebe5a1433c9804ba65a382e4f41e3084485d1b4d31996e4c992e38" + name = "github.com/containerd/fifo" + packages = ["."] + pruneopts = "UT" + revision = "a9fb20d87448d386e6d50b1f2e1fa70dcf0de43c" + +[[projects]] + digest = "1:bc38b83376aa09bdc1e889c00ce73cb748b2140d535bb5c76cb9823da6c7a98a" + name = "github.com/coreos/go-systemd" + packages = [ + "activation", + "sdjournal", + ] + pruneopts = "UT" + revision = "95778dfbb74eb7e4dbaf43bf7d71809650ef8076" + version = "v19" + +[[projects]] + digest = "1:6e2ff82d2fe11ee35ec8dceb4346b8144a761f1c8655592c4ebe99a92fcec327" + name = "github.com/coreos/pkg" + packages = ["dlopen"] + pruneopts = "UT" + revision = "97fdf19511ea361ae1c100dd393cc47f8dcfa1e1" + version = "v4" + +[[projects]] + branch = "master" + digest = "1:5a07b5363e4c2aa127a3afd1e8e323d3a288ba1d90d37793d2e14843f5b5b82e" name = "github.com/cortexproject/cortex" packages = [ "pkg/chunk", @@ -211,10 +257,9 @@ "pkg/util/middleware", "pkg/util/spanlogger", "pkg/util/validation", - "pkg/util/wire", ] pruneopts = "UT" - revision = "ff51bd3c7267184042ea4cf347e6d1fa24934c91" + revision = "ef492f6bbafb185bbe61ae7a6955b7a4af5f3d9a" [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" @@ -232,6 +277,93 @@ revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" version = "v3.2.0" +[[projects]] + digest = "1:699aca47d5af672db37b96102bb088edbf26f84f73d3dafff6fa917026eb6971" + name = "github.com/docker/distribution" + packages = ["registry/api/errcode"] + pruneopts = "UT" + revision = "2461543d988979529609e8cb6fca9ca190dc48da" + version = "v2.7.1" + +[[projects]] + branch = "master" + digest = "1:15c3bb44c339867455b8388edc16fbace9f3e5834cfa911389733b4ffd375496" + name = "github.com/docker/docker" + packages = [ + "api/types", + "api/types/backend", + "api/types/blkiodev", + "api/types/container", + "api/types/filters", + "api/types/mount", + "api/types/network", + "api/types/plugins/logdriver", + "api/types/registry", + "api/types/strslice", + "api/types/swarm", + "api/types/swarm/runtime", + "api/types/versions", + "daemon/logger", + "daemon/logger/jsonfilelog", + "daemon/logger/jsonfilelog/jsonlog", + "daemon/logger/loggerutils", + "daemon/logger/templates", + "errdefs", + "pkg/filenotify", + "pkg/ioutils", + "pkg/jsonmessage", + "pkg/longpath", + "pkg/plugingetter", + "pkg/plugins", + "pkg/plugins/transport", + "pkg/pools", + "pkg/progress", + "pkg/pubsub", + "pkg/streamformatter", + "pkg/stringid", + "pkg/tailfile", + "pkg/term", + "pkg/term/windows", + ] + pruneopts = "UT" + revision = "238f8eaa31aa74be843c81703fabf774863ec30c" + +[[projects]] + digest = "1:811c86996b1ca46729bad2724d4499014c4b9effd05ef8c71b852aad90deb0ce" + name = "github.com/docker/go-connections" + packages = [ + "nat", + "sockets", + "tlsconfig", + ] + pruneopts = "UT" + revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55" + version = "v0.4.0" + +[[projects]] + branch = "master" + digest = "1:2b126e77be4ab4b92cdb3924c87894dd76bf365ba282f358a13133e848aa0059" + name = "github.com/docker/go-metrics" + packages = ["."] + pruneopts = "UT" + revision = "b84716841b82eab644a0c64fc8b42d480e49add5" + +[[projects]] + branch = "master" + digest = "1:64aa7651bec9ea1eb3535fda3590661da0e6c225b746745976fa94c4126d652b" + name = "github.com/docker/go-plugins-helpers" + packages = ["sdk"] + pruneopts = "UT" + revision = "1e6269c305b8c75cfda1c8aa91349c38d7335814" + +[[projects]] + digest = "1:e95ef557dc3120984bb66b385ae01b4bb8ff56bcde28e7b0d1beed0cccc4d69f" + name = "github.com/docker/go-units" + packages = ["."] + pruneopts = "UT" + revision = "519db1ee28dcc9fd2474ae59fca29a810482bfb1" + version = "v0.4.0" + [[projects]] digest = "1:3762d59edaa6e5c71d5e594c020c8391f274ff283e9c30fb43c518ec59a3f9b3" name = "github.com/etcd-io/bbolt" @@ -248,6 +380,14 @@ revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" version = "v1.7.0" +[[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "github.com/fsnotify/fsnotify" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + [[projects]] branch = "master" digest = "1:4728aed43b5989e89bd5d88a00734adb2ec597e7823712cd05934c2d9fac89df" @@ -300,10 +440,11 @@ version = "v1.1.0" [[projects]] - digest = "1:452644cddfec8736ad410d9a5a4eacce21810873ceaa938ae373edf2f2c0fe84" + digest = "1:dfb2d8632b5a704b3b6c3eee885f18c23b0c2f5e942822f91ff8dbb58247ab07" name = "github.com/gogo/protobuf" packages = [ "gogoproto", + "io", "proto", "protoc-gen-gogo/descriptor", "sortkeys", @@ -386,8 +527,7 @@ version = "v0.2.0" [[projects]] - branch = "master" - digest = "1:848741e579410d2475b4f15411713e344320a3e766ce6e92700595159a62db08" + digest = "1:e57d9b8bf3a0e83d813416814937c4789ff89b06bccc65356912115af9977e7c" name = "github.com/gophercloud/gophercloud" packages = [ ".", @@ -404,7 +544,8 @@ "pagination", ] pruneopts = "UT" - revision = "07de4ce3c8b94e997c75205cfee74c33ffdaada7" + revision = "c2d73b246b48e239d3f03c455905e06fe26e33c3" + version = "v0.1.0" [[projects]] digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1" @@ -430,17 +571,6 @@ revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d" version = "v1.4.0" -[[projects]] - branch = "master" - digest = "1:86c1210529e69d69860f2bb3ee9ccce0b595aa3f9165e7dd1388e5c612915888" - name = "github.com/gregjones/httpcache" - packages = [ - ".", - "diskcache", - ] - pruneopts = "UT" - revision = "c63ab54fda8f77302f8d414e19933f2b6026a089" - [[projects]] digest = "1:1168584a5881d371e96cb0e66ef6db71d7cef0856cc7f311490bc856627f8328" name = "github.com/grpc-ecosystem/go-grpc-middleware" @@ -618,6 +748,14 @@ revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1" +[[projects]] + branch = "master" + digest = "1:906eb1ca3c8455e447b99a45237b2b9615b665608fd07ad12cce847dd9a1ec43" + name = "github.com/morikuni/aec" + packages = ["."] + pruneopts = "UT" + revision = "39771216ff4c63d11f5e604076f9c45e8be1067b" + [[projects]] branch = "master" digest = "1:9f07f801988b225662081432361c430cad8f5293b134e80bdf1998d14969d7a6" @@ -642,6 +780,25 @@ revision = "02a8604050d8466dd915307496174adb9be4593a" version = "v1.3.1" +[[projects]] + digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d" + name = "github.com/opencontainers/go-digest" + packages = ["."] + pruneopts = "UT" + revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" + version = "v1.0.0-rc1" + +[[projects]] + digest = "1:11db38d694c130c800d0aefb502fb02519e514dc53d9804ce51d1ad25ec27db6" + name = "github.com/opencontainers/image-spec" + packages = [ + "specs-go", + "specs-go/v1", + ] + pruneopts = "UT" + revision = "d60099175f88c47cd379c4738d158884749ed235" + version = "v1.0.1" + [[projects]] branch = "master" digest = "1:3173a0e98abdc5021301c4d34e6ac5ff8e6c792f3d22849c879ace70d5828978" @@ -678,14 +835,6 @@ pruneopts = "UT" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" -[[projects]] - digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852" - name = "github.com/peterbourgon/diskv" - packages = ["."] - pruneopts = "UT" - revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" - version = "v2.0.1" - [[projects]] digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" name = "github.com/pkg/errors" @@ -704,7 +853,7 @@ [[projects]] branch = "master" - digest = "1:8577a254ffb1b97e5c824fa32ccbc09bcbd327b2faa66b5abd83d7e6169a49b8" + digest = "1:dff66fce6bb8fa6111998bf3575e22aa3d0fd2560712a83de3390236d3cd1f6b" name = "github.com/prometheus/client_golang" packages = [ "api", @@ -712,6 +861,8 @@ "prometheus", "prometheus/internal", "prometheus/promauto", + "prometheus/promhttp", + "prometheus/testutil", ] pruneopts = "UT" revision = "c5e14697eaa7af985b2e326f1f5ed50bacb75c06" @@ -753,7 +904,7 @@ [[projects]] branch = "master" - digest = "1:c270fde3390cf824f004853135a8cb6347d013eab2d31e129bbae66219284284" + digest = "1:43edb14ccbe0d18f38bd55511250c39ccc3917c64a514a0e791408ac19a71558" name = "github.com/prometheus/prometheus" packages = [ "discovery", @@ -767,26 +918,29 @@ "discovery/kubernetes", "discovery/marathon", "discovery/openstack", + "discovery/refresh", "discovery/targetgroup", "discovery/triton", "discovery/zookeeper", "pkg/gate", "pkg/labels", + "pkg/modtimevfs", + "pkg/pool", "pkg/relabel", "pkg/textparse", "pkg/timestamp", "pkg/value", "promql", - "relabel", "storage", "storage/tsdb", + "template", "util/stats", "util/strutil", "util/testutil", "util/treecache", ] pruneopts = "UT" - revision = "0d1a69353e2864f9498e50fa51fa22bfb8346dcc" + revision = "e23fa22233cfbaa4fcea7abcd4e191ce5258870b" [[projects]] digest = "1:7aa5ae0ef5452ce26522f16677edee5016afeaa689f77e62e6b46374463b1884" @@ -821,6 +975,26 @@ revision = "f0a61d5e8ca1bcc7a607d6de3dfd51467791db88" version = "v2.1.0" +[[projects]] + branch = "master" + digest = "1:d716544630de6b0d07c24bd4690547b6db84a8f62f71939a2957aec1a7b824d2" + name = "github.com/shurcooL/httpfs" + packages = [ + "filter", + "union", + "vfsutil", + ] + pruneopts = "UT" + revision = "74dc9339e414ad069a8d04bba7e7aafd08043a25" + +[[projects]] + branch = "master" + digest = "1:98450c86949b8cdc4637b80c1c686ca955e503d3fbae9296d1f49c532895d281" + name = "github.com/shurcooL/vfsgen" + packages = ["."] + pruneopts = "UT" + revision = "6a9ea43bcacdf716a5c1b38efff722c07adf0069" + [[projects]] digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" name = "github.com/sirupsen/logrus" @@ -830,16 +1004,33 @@ version = "v1.3.0" [[projects]] - digest = "1:5da8ce674952566deae4dbc23d07c85caafc6cfa815b0b3e03e41979cedb8750" + digest = "1:ac83cf90d08b63ad5f7e020ef480d319ae890c208f8524622a2f3136e2686b02" + name = "github.com/stretchr/objx" + packages = ["."] + pruneopts = "UT" + revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c" + version = "v0.1.1" + +[[projects]] + digest = "1:b762f96c1183763894e8dabbac5f8e8d5821754b6e2686a8c398a174b7a58ff5" name = "github.com/stretchr/testify" packages = [ "assert", + "mock", "require", ] pruneopts = "UT" revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" version = "v1.3.0" +[[projects]] + branch = "master" + digest = "1:9ab2182297ebe5a1433c9804ba65a382e4f41e3084485d1b4d31996e4c992e38" + name = "github.com/tonistiigi/fifo" + packages = ["."] + pruneopts = "UT" + revision = "a9fb20d87448d386e6d50b1f2e1fa70dcf0de43c" + [[projects]] branch = "master" digest = "1:c9fac76a6828c9dd4bf2a73804c35f28b9d15db602e11a7ffe87f44d52c8ab3b" @@ -878,8 +1069,8 @@ version = "v2.0.0" [[projects]] - branch = "master" - digest = "1:81403343bc9a102e3c924f87ad81e5a13bb7c36211714475c906853f4e887933" + branch = "server-listen-addr" + digest = "1:0184d699d4cbbbc3073fbbdd7cc0c8592d484c6f23914c89fb6d218e90de171a" name = "github.com/weaveworks/common" packages = [ "aws", @@ -896,7 +1087,8 @@ "user", ] pruneopts = "UT" - revision = "81a1a4d158e60de72dbead600ec011fb90344f8c" + revision = "5bf824591a6567784789cf9b2169f74f162bf80d" + source = "https://github.com/tomwilkie/weaveworks-common" [[projects]] digest = "1:bb40f7ff970145324f2a2acafdff3a23ed3f05db49cb5eb519b3d6bee86a5887" @@ -945,7 +1137,7 @@ [[projects]] branch = "master" - digest = "1:1d4b98f6810f39d93cba6ac580325528e02a6ebccafaa7628fb232cd8450b177" + digest = "1:1ffd895348a1d8f406811326cae5de5ba6de04e7a9ed03f26e8d39fc7ef27621" name = "golang.org/x/net" packages = [ "bpf", @@ -957,9 +1149,11 @@ "idna", "internal/iana", "internal/socket", + "internal/socks", "internal/timeseries", "ipv4", "ipv6", + "proxy", "trace", ] pruneopts = "UT" @@ -1034,7 +1228,7 @@ [[projects]] branch = "master" - digest = "1:d594bebb1e46761948a5162ce831bdee8bbf54204a9f87c5687143b4efe10cde" + digest = "1:961dd085b9c55912dc9c7d05e83bdad3a491b302fa7a844caa314d66a78734d9" name = "google.golang.org/api" packages = [ "cloudresourcemanager/v1", @@ -1054,7 +1248,7 @@ "transport/http/internal/propagation", ] pruneopts = "UT" - revision = "032faecc3e7e2c445ec37a1b1ec4e5a3016d96f2" + revision = "5213b809086156e6e2b262a41394993fcff97439" [[projects]] digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" @@ -1095,17 +1289,27 @@ revision = "6909d8a4a91b6d3fd1c4580b6e35816be4706fef" [[projects]] - digest = "1:10be9918abb568296ca66b6967197d0183e18d934e62f0f542e2e04a8b503270" + digest = "1:10488712ab5f5da69a7da557c169824c247b63219af7f072318919ba352bee7a" name = "google.golang.org/grpc" packages = [ ".", "balancer", "balancer/base", + "balancer/grpclb", + "balancer/grpclb/grpc_lb_v1", "balancer/roundrobin", "binarylog/grpc_binarylog_v1", "codes", "connectivity", "credentials", + "credentials/alts", + "credentials/alts/internal", + "credentials/alts/internal/authinfo", + "credentials/alts/internal/conn", + "credentials/alts/internal/handshaker", + "credentials/alts/internal/handshaker/service", + "credentials/alts/internal/proto/grpc_gcp", + "credentials/google", "credentials/internal", "credentials/oauth", "encoding", @@ -1115,6 +1319,7 @@ "health/grpc_health_v1", "internal", "internal/backoff", + "internal/balancerload", "internal/binarylog", "internal/channelz", "internal/envconfig", @@ -1134,8 +1339,8 @@ "tap", ] pruneopts = "UT" - revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8" - version = "v1.17.0" + revision = "501c41df7f472c740d0674ff27122f3f48c80ce7" + version = "v1.21.1" [[projects]] digest = "1:c06d9e11d955af78ac3bbb26bd02e01d2f61f689e1a3bce2ef6fb683ef8a7f2d" @@ -1187,10 +1392,10 @@ version = "v2.2.2" [[projects]] - digest = "1:0d299a04c6472e4458461d7034c76d014cc6f632a3262cbf21d123b19ce13e65" + branch = "master" + digest = "1:b2e959d92a38ffc25142da8e8bf4fefe0e5e687ecb871fabaac58db0497304df" name = "k8s.io/api" packages = [ - "admissionregistration/v1alpha1", "admissionregistration/v1beta1", "apps/v1", "apps/v1beta1", @@ -1207,15 +1412,20 @@ "batch/v1beta1", "batch/v2alpha1", "certificates/v1beta1", + "coordination/v1", "coordination/v1beta1", "core/v1", "events/v1beta1", "extensions/v1beta1", "networking/v1", + "networking/v1beta1", + "node/v1alpha1", + "node/v1beta1", "policy/v1beta1", "rbac/v1", "rbac/v1alpha1", "rbac/v1beta1", + "scheduling/v1", "scheduling/v1alpha1", "scheduling/v1beta1", "settings/v1alpha1", @@ -1224,7 +1434,7 @@ "storage/v1beta1", ] pruneopts = "UT" - revision = "05914d821849" + revision = "9b8cae951d65ea28a341b3262d38a058d0935f7c" [[projects]] digest = "1:846bcc1ec56accfcb542fa8834d3013b64e7930eb6e9789a7be1bb6448567265" @@ -1274,13 +1484,12 @@ revision = "2b1284ed4c93" [[projects]] - digest = "1:9edb9a30d4ec54889d1bb3137f0a24915a0b4306ee95f156ef6a111f755816b3" + digest = "1:d6168474843596c732e8e457ef6f66655a86a135b25a408d7f913b38c056819c" name = "k8s.io/client-go" packages = [ "discovery", "kubernetes", "kubernetes/scheme", - "kubernetes/typed/admissionregistration/v1alpha1", "kubernetes/typed/admissionregistration/v1beta1", "kubernetes/typed/apps/v1", "kubernetes/typed/apps/v1beta1", @@ -1297,15 +1506,20 @@ "kubernetes/typed/batch/v1beta1", "kubernetes/typed/batch/v2alpha1", "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/coordination/v1", "kubernetes/typed/coordination/v1beta1", "kubernetes/typed/core/v1", "kubernetes/typed/events/v1beta1", "kubernetes/typed/extensions/v1beta1", "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1beta1", + "kubernetes/typed/node/v1alpha1", + "kubernetes/typed/node/v1beta1", "kubernetes/typed/policy/v1beta1", "kubernetes/typed/rbac/v1", "kubernetes/typed/rbac/v1alpha1", "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/scheduling/v1", "kubernetes/typed/scheduling/v1alpha1", "kubernetes/typed/scheduling/v1beta1", "kubernetes/typed/settings/v1alpha1", @@ -1325,16 +1539,15 @@ "tools/pager", "tools/reference", "transport", - "util/buffer", "util/cert", "util/connrotation", "util/flowcontrol", - "util/integer", + "util/keyutil", "util/retry", "util/workqueue", ] pruneopts = "UT" - revision = "a47917edff34" + revision = "1a26190bd76a9017e289958b9fba936430aa3704" [[projects]] digest = "1:e2999bf1bb6eddc2a6aa03fe5e6629120a53088926520ca3b4765f77d7ff7eab" @@ -1344,6 +1557,18 @@ revision = "a5bc97fbc634d635061f3146511332c7e313a55a" version = "v0.1.0" +[[projects]] + branch = "master" + digest = "1:03ce1a3e8094febc17dfaf3bfc7a445fb964e4fa96d3443822505dfc8567b648" + name = "k8s.io/utils" + packages = [ + "buffer", + "integer", + "trace", + ] + pruneopts = "UT" + revision = "6999998975a717e7f5fc2a7476497044cb111854" + [[projects]] digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849" name = "sigs.k8s.io/yaml" @@ -1357,8 +1582,10 @@ analyzer-version = 1 input-imports = [ "github.com/bmatcuk/doublestar", + "github.com/coreos/go-systemd/sdjournal", "github.com/cortexproject/cortex/pkg/chunk", "github.com/cortexproject/cortex/pkg/chunk/encoding", + "github.com/cortexproject/cortex/pkg/chunk/local", "github.com/cortexproject/cortex/pkg/chunk/storage", "github.com/cortexproject/cortex/pkg/ingester/client", "github.com/cortexproject/cortex/pkg/ingester/index", @@ -1366,11 +1593,17 @@ "github.com/cortexproject/cortex/pkg/util", "github.com/cortexproject/cortex/pkg/util/flagext", "github.com/cortexproject/cortex/pkg/util/validation", - "github.com/cortexproject/cortex/pkg/util/wire", + "github.com/docker/docker/api/types/plugins/logdriver", + "github.com/docker/docker/daemon/logger", + "github.com/docker/docker/daemon/logger/jsonfilelog", + "github.com/docker/docker/daemon/logger/templates", + "github.com/docker/docker/pkg/ioutils", + "github.com/docker/go-plugins-helpers/sdk", "github.com/fatih/color", "github.com/go-kit/kit/log", "github.com/go-kit/kit/log/level", "github.com/gogo/protobuf/gogoproto", + "github.com/gogo/protobuf/io", "github.com/gogo/protobuf/proto", "github.com/gogo/protobuf/types", "github.com/golang/snappy", @@ -1378,29 +1611,50 @@ "github.com/gorilla/websocket", "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc", "github.com/hpcloud/tail", + "github.com/jmespath/go-jmespath", + "github.com/mitchellh/mapstructure", "github.com/mwitkow/go-grpc-middleware", "github.com/opentracing/opentracing-go", "github.com/pkg/errors", "github.com/prometheus/client_golang/prometheus", "github.com/prometheus/client_golang/prometheus/promauto", + "github.com/prometheus/client_golang/prometheus/promhttp", + "github.com/prometheus/client_golang/prometheus/testutil", + "github.com/prometheus/client_model/go", + "github.com/prometheus/common/config", + "github.com/prometheus/common/expfmt", "github.com/prometheus/common/model", "github.com/prometheus/common/version", "github.com/prometheus/prometheus/discovery", "github.com/prometheus/prometheus/discovery/config", "github.com/prometheus/prometheus/discovery/targetgroup", "github.com/prometheus/prometheus/pkg/labels", + "github.com/prometheus/prometheus/pkg/modtimevfs", + "github.com/prometheus/prometheus/pkg/pool", "github.com/prometheus/prometheus/pkg/relabel", - "github.com/prometheus/prometheus/relabel", + "github.com/prometheus/prometheus/pkg/textparse", + "github.com/prometheus/prometheus/promql", + "github.com/prometheus/prometheus/template", + "github.com/shurcooL/httpfs/filter", + "github.com/shurcooL/httpfs/union", + "github.com/shurcooL/vfsgen", "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/mock", "github.com/stretchr/testify/require", + "github.com/tonistiigi/fifo", "github.com/weaveworks/common/httpgrpc", + "github.com/weaveworks/common/httpgrpc/server", + "github.com/weaveworks/common/logging", "github.com/weaveworks/common/middleware", "github.com/weaveworks/common/server", "github.com/weaveworks/common/tracing", "github.com/weaveworks/common/user", "golang.org/x/net/context", "google.golang.org/grpc", + "google.golang.org/grpc/codes", "google.golang.org/grpc/health/grpc_health_v1", + "google.golang.org/grpc/metadata", + "google.golang.org/grpc/status", "gopkg.in/alecthomas/kingpin.v2", "gopkg.in/fsnotify.v1", "gopkg.in/yaml.v2", diff --git a/Gopkg.toml b/Gopkg.toml index e35786b0c7221..01e104fe0de51 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -30,7 +30,8 @@ [[constraint]] name = "github.com/weaveworks/common" - branch = "master" + source = "https://github.com/tomwilkie/weaveworks-common" + branch = "server-listen-addr" [[constraint]] name = "gopkg.in/fsnotify.v1" @@ -70,3 +71,10 @@ name = "github.com/hpcloud/tail" source = "github.com/grafana/tail" branch = "master" + +[[override]] + name = "k8s.io/client-go" + revision = "1a26190bd76a9017e289958b9fba936430aa3704" +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.3.0" diff --git a/Makefile b/Makefile index e7c27e0f41899..8c7e8cfcbf0cd 100644 --- a/Makefile +++ b/Makefile @@ -1,80 +1,64 @@ -.PHONY: all test clean images protos .DEFAULT_GOAL := all +.PHONY: all images check-generated-files logcli loki loki-debug promtail promtail-debug loki-canary lint test clean yacc protos +.PHONY: helm helm-install helm-upgrade helm-publish helm-debug helm-clean +.PHONY: docker-driver docker-driver-clean docker-driver-enable docker-driver-push +.PHONY: push-images push-latest save-images load-images promtail-image loki-image build-image +.PHONY: benchmark-store +############# +# Variables # +############# -CHARTS := production/helm/loki production/helm/promtail production/helm/loki-stack +DOCKER_IMAGE_DIRS := $(patsubst %/Dockerfile,%,$(DOCKERFILES)) +IMAGE_NAMES := $(foreach dir,$(DOCKER_IMAGE_DIRS),$(patsubst %,$(IMAGE_PREFIX)%,$(shell basename $(dir)))) -# Boiler plate for bulding Docker containers. -# All this must go at top of file I'm afraid. -IMAGE_PREFIX ?= grafana/ +# Certain aspects of the build are done in containers for consistency (e.g. yacc/protobuf generation) +# If you have the correct tools installed and you want to speed up development you can run +# make BUILD_IN_CONTAINER=false target +# or you can override this with an environment variable +BUILD_IN_CONTAINER ?= true +BUILD_IMAGE_VERSION := "0.2.1" + +# Docker image info +IMAGE_PREFIX ?= grafana IMAGE_TAG := $(shell ./tools/image-tag) -UPTODATE := .uptodate + +# Version info for binaries GIT_REVISION := $(shell git rev-parse --short HEAD) GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) - -# Building Docker images is now automated. The convention is every directory -# with a Dockerfile in it builds an image calls quay.io/grafana/loki-. -# Dependencies (i.e. things that go in the image) still need to be explicitly -# declared. -%/$(UPTODATE): %/Dockerfile - $(SUDO) docker build -t $(IMAGE_PREFIX)$(shell basename $(@D)) $(@D)/ - $(SUDO) docker tag $(IMAGE_PREFIX)$(shell basename $(@D)) $(IMAGE_PREFIX)$(shell basename $(@D)):$(IMAGE_TAG) - touch $@ - # We don't want find to scan inside a bunch of directories, to accelerate the # 'make: Entering directory '/go/src/github.com/grafana/loki' phase. DONT_FIND := -name tools -prune -o -name vendor -prune -o -name .git -prune -o -name .cache -prune -o -name .pkg -prune -o -# Get a list of directories containing Dockerfiles -DOCKERFILES := $(shell find . $(DONT_FIND) -type f -name 'Dockerfile' -print) -UPTODATE_FILES := $(patsubst %/Dockerfile,%/$(UPTODATE),$(DOCKERFILES)) -DOCKER_IMAGE_DIRS := $(patsubst %/Dockerfile,%,$(DOCKERFILES)) -IMAGE_NAMES := $(foreach dir,$(DOCKER_IMAGE_DIRS),$(patsubst %,$(IMAGE_PREFIX)%,$(shell basename $(dir)))) -images: - $(info $(patsubst %,%:$(IMAGE_TAG),$(IMAGE_NAMES))) - @echo > /dev/null +# These are all the application files, they are included in the various binary rules as dependencies +# to make sure binaries are rebuilt if any source files change. +APP_GO_FILES := $(shell find . $(DONT_FIND) -name .y.go -prune -o -name .pb.go -prune -o -name cmd -prune -o -type f -name '*.go' -print) + +# Build flags +VPREFIX := github.com/grafana/loki/vendor/github.com/prometheus/common/version +GO_FLAGS := -ldflags "-extldflags \"-static\" -s -w -X $(VPREFIX).Branch=$(GIT_BRANCH) -X $(VPREFIX).Version=$(IMAGE_TAG) -X $(VPREFIX).Revision=$(GIT_REVISION)" -tags netgo +# Per some websites I've seen to add `-gcflags "all=-N -l"`, the gcflags seem poorly if at all documented +# the best I could dig up is -N disables optimizations and -l disables inlining which should make debugging match source better. +# Also remove the -s and -w flags present in the normal build which strip the symbol table and the DWARF symbol table. +DEBUG_GO_FLAGS := -gcflags "all=-N -l" -ldflags "-extldflags \"-static\" -X $(VPREFIX).Branch=$(GIT_BRANCH) -X $(VPREFIX).Version=$(IMAGE_TAG) -X $(VPREFIX).Revision=$(GIT_REVISION)" -tags netgo -# Generating proto code is automated. +NETGO_CHECK = @strings $@ | grep cgo_stub\\\.go >/dev/null || { \ + rm $@; \ + echo "\nYour go standard library was built without the 'netgo' build tag."; \ + echo "To fix that, run"; \ + echo " sudo go clean -i net"; \ + echo " sudo go install -tags netgo std"; \ + false; \ +} + +# Protobuf files PROTO_DEFS := $(shell find . $(DONT_FIND) -type f -name '*.proto' -print) -PROTO_GOS := $(patsubst %.proto,%.pb.go,$(PROTO_DEFS)) \ - vendor/github.com/cortexproject/cortex/pkg/ring/ring.pb.go \ - vendor/github.com/cortexproject/cortex/pkg/ingester/client/cortex.pb.go \ - vendor/github.com/cortexproject/cortex/pkg/chunk/storage/caching_index_client.pb.go +PROTO_GOS := $(patsubst %.proto,%.pb.go,$(PROTO_DEFS)) -# Generating yacc code is automated. +# Yacc Files YACC_DEFS := $(shell find . $(DONT_FIND) -type f -name *.y -print) -YACC_GOS := $(patsubst %.y,%.go,$(YACC_DEFS)) - -# Building binaries is now automated. The convention is to build a binary -# for every directory with main.go in it, in the ./cmd directory. -MAIN_GO := $(shell find . $(DONT_FIND) -type f -name 'main.go' -print) -EXES := $(foreach exe, $(patsubst ./cmd/%/main.go, %, $(MAIN_GO)), ./cmd/$(exe)/$(exe)) -GO_FILES := $(shell find . $(DONT_FIND) -name cmd -prune -o -type f -name '*.go' -print) -define dep_exe -$(1): $(dir $(1))/main.go $(GO_FILES) $(PROTO_GOS) $(YACC_GOS) -$(dir $(1))$(UPTODATE): $(1) -endef -$(foreach exe, $(EXES), $(eval $(call dep_exe, $(exe)))) - -# Manually declared dependancies and what goes into each exe -pkg/logproto/logproto.pb.go: pkg/logproto/logproto.proto -vendor/github.com/cortexproject/cortex/pkg/ring/ring.pb.go: vendor/github.com/cortexproject/cortex/pkg/ring/ring.proto -vendor/github.com/cortexproject/cortex/pkg/ingester/client/cortex.pb.go: vendor/github.com/cortexproject/cortex/pkg/ingester/client/cortex.proto -vendor/github.com/cortexproject/cortex/pkg/chunk/storage/caching_index_client.pb.go: vendor/github.com/cortexproject/cortex/pkg/chunk/storage/caching_index_client.proto -pkg/parser/labels.go: pkg/parser/labels.y -pkg/parser/matchers.go: pkg/parser/matchers.y -all: $(UPTODATE_FILES) -test: $(PROTO_GOS) $(YACC_GOS) -yacc: $(YACC_GOS) -protos: $(PROTO_GOS) -yacc: $(YACC_GOS) - -# And now what goes into each image -loki-build-image/$(UPTODATE): loki-build-image/* +YACC_GOS := $(patsubst %.y,%.y.go,$(YACC_DEFS)) -# All the boiler plate for building golang follows: -SUDO := $(shell docker info >/dev/null 2>&1 || echo "sudo -E") -BUILD_IN_CONTAINER := true # RM is parameterized to allow CircleCI to run builds, as it # currently disallows `docker run --rm`. This value is overridden # in circle.yml @@ -84,122 +68,294 @@ RM := --rm # in any custom cloudbuild.yaml files TTY := --tty -VPREFIX := github.com/grafana/loki/vendor/github.com/prometheus/common/version -GO_FLAGS := -ldflags "-extldflags \"-static\" -s -w -X $(VPREFIX).Branch=$(GIT_BRANCH) -X $(VPREFIX).Version=$(IMAGE_TAG) -X $(VPREFIX).Revision=$(GIT_REVISION)" -tags netgo +################ +# Main Targets # +################ -NETGO_CHECK = @strings $@ | grep cgo_stub\\\.go >/dev/null || { \ - rm $@; \ - echo "\nYour go standard library was built without the 'netgo' build tag."; \ - echo "To fix that, run"; \ - echo " sudo go clean -i net"; \ - echo " sudo go install -tags netgo std"; \ - false; \ -} +all: promtail logcli loki loki-canary check-generated-files -ifeq ($(BUILD_IN_CONTAINER),true) -$(EXES) $(PROTO_GOS) $(YACC_GOS) lint test shell check-generated-files: loki-build-image/$(UPTODATE) +# This is really a check for the CI to make sure generated files are built and checked in manually +check-generated-files: yacc protos + @if ! (git diff --exit-code $(YACC_GOS) $(PROTO_GOS)); then \ + echo "\nChanges found in either generated protos or yaccs"; \ + echo "Run 'make all' and commit the changes to fix this error."; \ + echo "If you are actively developing these files you can ignore this error"; \ + echo "(Don't forget to check in the generated files when finished)\n"; \ + exit 1; \ + fi + + +########## +# Logcli # +########## + +logcli: yacc cmd/logcli/logcli + +cmd/logcli/logcli: $(APP_GO_FILES) cmd/logcli/main.go + CGO_ENABLED=0 go build $(GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +######## +# Loki # +######## + +loki: protos yacc cmd/loki/loki +loki-debug: protos yacc cmd/loki/loki-debug + +cmd/loki/loki: $(APP_GO_FILES) cmd/loki/main.go + CGO_ENABLED=0 go build $(GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +cmd/loki/loki-debug: $(APP_GO_FILES) cmd/loki/main.go + CGO_ENABLED=0 go build $(DEBUG_GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +############### +# Loki-Canary # +############### + +loki-canary: protos yacc cmd/loki-canary/loki-canary + +cmd/loki-canary/loki-canary: $(APP_GO_FILES) cmd/loki-canary/main.go + CGO_ENABLED=0 go build $(GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +############ +# Promtail # +############ + +promtail: yacc cmd/promtail/promtail +promtail-debug: yacc cmd/promtail/promtail-debug + +# Rule to generate promtail static assets file +pkg/promtail/server/ui/assets_vfsdata.go: + @echo ">> writing assets" + GOOS=$(shell go env GOHOSTOS) go generate -x -v ./pkg/promtail/server/ui + +cmd/promtail/promtail: $(APP_GO_FILES) pkg/promtail/server/ui/assets_vfsdata.go cmd/promtail/main.go + CGO_ENABLED=0 go build $(GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +cmd/promtail/promtail-debug: $(APP_GO_FILES) pkg/promtail/server/ui/assets_vfsdata.go cmd/promtail/main.go + CGO_ENABLED=0 go build $(DEBUG_GO_FLAGS) -o $@ ./$(@D) + $(NETGO_CHECK) + +######## +# Lint # +######## + +lint: + GOGC=20 golangci-lint run + +######## +# Test # +######## + +test: all + go test -p=8 ./... + +######### +# Clean # +######### + +clean: + rm -rf cmd/promtail/promtail pkg/promtail/server/ui/assets_vfsdata.go + rm -rf cmd/loki/loki + rm -rf cmd/logcli/logcli + rm -rf cmd/loki-canary/loki-canary + rm -rf .cache + rm -rf cmd/docker-driver/rootfs + go clean ./... + +######### +# YACCs # +######### + +yacc: $(YACC_GOS) + +%.y.go: %.y +ifeq ($(BUILD_IN_CONTAINER),true) + # I wish we could make this a multiline variable however you can't pass more than simple arguments to them @mkdir -p $(shell pwd)/.pkg @mkdir -p $(shell pwd)/.cache $(SUDO) docker run $(RM) $(TTY) -i \ -v $(shell pwd)/.cache:/go/cache \ -v $(shell pwd)/.pkg:/go/pkg \ -v $(shell pwd):/go/src/github.com/grafana/loki \ - $(IMAGE_PREFIX)loki-build-image $@; + $(IMAGE_PREFIX)/loki-build-image:$(BUILD_IMAGE_VERSION) $@; +else + goyacc -p $(basename $(notdir $<)) -o $@ $< +endif + +############# +# Protobufs # +############# +protos: $(PROTO_GOS) + +%.pb.go: $(PROTO_DEFS) +ifeq ($(BUILD_IN_CONTAINER),true) + @mkdir -p $(shell pwd)/.pkg + @mkdir -p $(shell pwd)/.cache + $(SUDO) docker run $(RM) $(TTY) -i \ + -v $(shell pwd)/.cache:/go/cache \ + -v $(shell pwd)/.pkg:/go/pkg \ + -v $(shell pwd):/go/src/github.com/grafana/loki \ + $(IMAGE_PREFIX)/loki-build-image:$(BUILD_IMAGE_VERSION) $@; else + case "$@" in \ + vendor*) \ + protoc -I ./vendor:./$(@D) --gogoslick_out=plugins=grpc:./vendor ./$(patsubst %.pb.go,%.proto,$@); \ + ;; \ + *) \ + protoc -I ./vendor:./$(@D) --gogoslick_out=Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,plugins=grpc:./$(@D) ./$(patsubst %.pb.go,%.proto,$@); \ + ;; \ + esac +endif + + +######## +# Helm # +######## -$(EXES): loki-build-image/$(UPTODATE) +CHARTS := production/helm/loki production/helm/promtail production/helm/loki-stack + +helm: + -rm -f production/helm/*/requirements.lock + @set -e; \ + helm init -c; \ + for chart in $(CHARTS); do \ + helm dependency build $$chart; \ + helm lint $$chart; \ + helm package $$chart; \ + done + rm -f production/helm/*/requirements.lock + +helm-install: + kubectl apply -f tools/helm.yaml + helm init --wait --service-account helm --upgrade + $(MAKE) helm-upgrade + +helm-upgrade: helm + helm upgrade --wait --install $(ARGS) loki-stack ./production/helm/loki-stack \ + --set promtail.image.tag=$(IMAGE_TAG) --set loki.image.tag=$(IMAGE_TAG) -f tools/dev.values.yaml + +helm-publish: helm + cp production/helm/README.md index.md + git config user.email "$CIRCLE_USERNAME@users.noreply.github.com" + git config user.name "${CIRCLE_USERNAME}" + git checkout gh-pages || (git checkout --orphan gh-pages && git rm -rf . > /dev/null) + mkdir -p charts + mv *.tgz index.md charts/ + helm repo index charts/ + git add charts/ + git commit -m "[skip ci] Publishing helm charts: ${CIRCLE_SHA1}" + git push origin gh-pages + +helm-debug: ARGS=--dry-run --debug +helm-debug: helm-upgrade + +helm-clean: + -helm delete --purge loki-stack + +################# +# Docker Driver # +################# + +PLUGIN_TAG ?= $(IMAGE_TAG) + +docker-driver: docker-driver-clean cmd/docker-driver/docker-driver + mkdir cmd/docker-driver/rootfs + docker build -t rootfsimage cmd/docker-driver + ID=$$(docker create rootfsimage true) && \ + (docker export $$ID | tar -x -C cmd/docker-driver/rootfs) && \ + docker rm -vf $$ID + docker rmi rootfsimage -f + docker plugin create grafana/loki-docker-driver:$(PLUGIN_TAG) cmd/docker-driver + +cmd/docker-driver/docker-driver: $(APP_GO_FILES) CGO_ENABLED=0 go build $(GO_FLAGS) -o $@ ./$(@D) $(NETGO_CHECK) -%.pb.go: loki-build-image/$(UPTODATE) - case "$@" in \ - vendor*) \ - protoc -I ./vendor:./$(@D) --gogoslick_out=plugins=grpc:./vendor ./$(patsubst %.pb.go,%.proto,$@); \ - ;; \ - *) \ - protoc -I ./vendor:./$(@D) --gogoslick_out=Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,plugins=grpc:./$(@D) ./$(patsubst %.pb.go,%.proto,$@); \ - ;; \ - esac - -%.go: %.y - goyacc -p $(basename $(notdir $<)) -o $@ $< +docker-driver-push: docker-driver + docker plugin push grafana/loki-docker-driver:$(PLUGIN_TAG) -lint: loki-build-image/$(UPTODATE) - gometalinter ./... +docker-driver-enable: + docker plugin enable grafana/loki-docker-driver:$(PLUGIN_TAG) -check-generated-files: loki-build-image/$(UPTODATE) yacc protos - @git diff-files || (echo "changed files; failing check" && exit 1) +docker-driver-clean: + -docker plugin disable grafana/loki-docker-driver:$(IMAGE_TAG) + -docker plugin rm grafana/loki-docker-driver:$(IMAGE_TAG) + rm -rf cmd/docker-driver/rootfs -test: loki-build-image/$(UPTODATE) - go test ./... -shell: loki-build-image/$(UPTODATE) - bash +########## +# Images # +########## -endif +images: promtail-image loki-image loki-canary-image docker-driver + +IMAGE_NAMES := grafana/loki grafana/promtail grafana/loki-canary save-images: @set -e; \ mkdir -p images; \ for image_name in $(IMAGE_NAMES); do \ - if ! echo $$image_name | grep build; then \ - docker save $$image_name:$(IMAGE_TAG) -o images/$$(echo $$image_name | tr "/" _):$(IMAGE_TAG); \ - fi \ + echo ">> saving image $$image_name:$(IMAGE_TAG)"; \ + docker save $$image_name:$(IMAGE_TAG) -o images/$$(echo $$image_name | tr "/" _):$(IMAGE_TAG); \ done load-images: @set -e; \ mkdir -p images; \ for image_name in $(IMAGE_NAMES); do \ - if ! echo $$image_name | grep build; then \ - docker load -i images/$$(echo $$image_name | tr "/" _):$(IMAGE_TAG); \ - fi \ + docker load -i images/$$(echo $$image_name | tr "/" _):$(IMAGE_TAG); \ done push-images: @set -e; \ for image_name in $(IMAGE_NAMES); do \ - if ! echo $$image_name | grep build; then \ - docker push $$image_name:$(IMAGE_TAG); \ - fi \ + docker push $$image_name:$(IMAGE_TAG); \ done push-latest: @set -e; \ for image_name in $(IMAGE_NAMES); do \ - if ! echo $$image_name | grep build; then \ - docker tag $$image_name:$(IMAGE_TAG) $$image_name:latest; \ - docker tag $$image_name:$(IMAGE_TAG) $$image_name:master; \ - docker push $$image_name:latest; \ - docker push $$image_name:master; \ - fi \ + docker tag $$image_name:$(IMAGE_TAG) $$image_name:latest; \ + docker tag $$image_name:$(IMAGE_TAG) $$image_name:master; \ + docker push $$image_name:latest; \ + docker push $$image_name:master; \ done -helm: - @set -e; \ - helm init -c; \ - for chart in $(CHARTS); do \ - helm lint $$chart; \ - helm dependency build $$chart; \ - helm package $$chart; \ - done - rm -f production/helm/*/requirements.lock -helm-publish: helm - cp production/helm/README.md index.md - git config user.email "$CIRCLE_USERNAME@users.noreply.github.com" - git config user.name "${CIRCLE_USERNAME}" - git checkout gh-pages || (git checkout --orphan gh-pages && git rm -rf . > /dev/null) - mkdir -p charts - mv *.tgz index.md charts/ - helm repo index charts/ - git add charts/ - git commit -m "[skip ci] Publishing helm charts: ${CIRCLE_SHA1}" - git push origin gh-pages +promtail-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/promtail -f cmd/promtail/Dockerfile . + $(SUDO) docker tag $(IMAGE_PREFIX)/promtail $(IMAGE_PREFIX)/promtail:$(IMAGE_TAG) +promtail-debug-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/promtail -f cmd/promtail/Dockerfile.debug . + $(SUDO) docker tag $(IMAGE_PREFIX)/promtail-debug $(IMAGE_PREFIX)/promtail-debug:$(IMAGE_TAG) -clean: - $(SUDO) docker rmi $(IMAGE_NAMES) >/dev/null 2>&1 || true - rm -rf $(UPTODATE_FILES) $(EXES) .cache - go clean ./... +loki-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/loki -f cmd/loki/Dockerfile . + $(SUDO) docker tag $(IMAGE_PREFIX)/loki $(IMAGE_PREFIX)/loki:$(IMAGE_TAG) +loki-debug-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/loki -f cmd/loki/Dockerfile.debug . + $(SUDO) docker tag $(IMAGE_PREFIX)/loki-debug $(IMAGE_PREFIX)/loki-debug:$(IMAGE_TAG) + +loki-canary-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/loki-canary -f cmd/loki-canary/Dockerfile . + $(SUDO) docker tag $(IMAGE_PREFIX)/loki-canary $(IMAGE_PREFIX)/loki-canary:$(IMAGE_TAG) + +build-image: + $(SUDO) docker build -t $(IMAGE_PREFIX)/loki-build-image -f loki-build-image/Dockerfile . + $(SUDO) docker tag $(IMAGE_PREFIX)/loki-build-image $(IMAGE_PREFIX)/loki-build-image:$(IMAGE_TAG) + + +######## +# Misc # +######## + +benchmark-store: + go run ./pkg/storage/hack/main.go + go test ./pkg/storage/ -bench=. -benchmem -memprofile memprofile.out -cpuprofile cpuprofile.out diff --git a/README.md b/README.md index fc4c72a9d242e..998eeb0b0908c 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,11 @@ Once you have promtail, Loki, and Grafana running, continue with [our usage docs - [API documentation](./docs/api.md) for alternative ways of getting logs into Loki. - [Operations](./docs/operations.md) for important aspects of running Loki. -- [Promtail](./docs/promtail-setup.md) on how to configure the agent that tails your logs. +- [Promtail](./docs/promtail.md) is an agent which can tail your log files and push them to Loki. +- [Processing Log Lines](./docs/logentry/processing-log-lines.md) for detailed log processing pipeline documentation +- [Docker Logging Driver](./cmd/docker-driver/README.md) is a docker plugin to send logs directly to Loki from Docker containers. - [Logcli](./docs/logcli.md) on how to query your logs without Grafana. +- [Loki Canary](./docs/canary/README.md) for monitoring your Loki installation for missing logs. - [Troubleshooting](./docs/troubleshooting.md) for help around frequent error messages. - [Usage](./docs/usage.md) for how to set up a Loki datasource in Grafana and query your logs. @@ -55,12 +58,16 @@ Your feedback is always welcome. ## Further Reading - The original [design doc](https://docs.google.com/document/d/11tjK_lvp1-SVsFZjgOTr1vV3-q6vBAsZYIQ5ZeYBkyM/view) for Loki is a good source for discussion of the motivation and design decisions. +- Callum Styan's March 2019 DevOpsDays Vancouver talk "[Grafana Loki: Log Aggregation for Incident Investigations][devopsdays19-talk]". +- Grafana Labs blog post "[How We Designed Loki to Work Easily Both as Microservices and as Monoliths][architecture-blog]". - Julien Garcia Gonzalez' March 2019 blog post "[Grafana Logging using Loki][giant-swarm-blog]". -- Tom Wilkie's early-2019 CNCF Paris/FODEM talk "[Grafana Loki: like Prometheus, but for logs][fosdem19-talk]" ([slides][fosdem19-slides], [video][fosdem19-video]). +- Tom Wilkie's early-2019 CNCF Paris/FOSDEM talk "[Grafana Loki: like Prometheus, but for logs][fosdem19-talk]" ([slides][fosdem19-slides], [video][fosdem19-video]). - David Kaltschmidt's KubeCon 2018 talk "[On the OSS Path to Full Observability with Grafana][kccna18-event]" ([slides][kccna18-slides], [video][kccna18-video]) on how Loki fits into a cloud-native environment. - Goutham Veeramachaneni's blog post "[Loki: Prometheus-inspired, open source logging for cloud natives](https://grafana.com/blog/2018/12/12/loki-prometheus-inspired-open-source-logging-for-cloud-natives/)" on details of the Loki architectire. - David Kaltschmidt's blog post "[Closer look at Grafana's user interface for Loki](https://grafana.com/blog/2019/01/02/closer-look-at-grafanas-user-interface-for-loki/)" on the ideas that went into the logging user interface. +[devopsdays19-talk]: https://grafana.com/blog/2019/05/06/how-loki-correlates-metrics-and-logs-and-saves-you-money/ +[architecture-blog]: https://grafana.com/blog/2019/04/15/how-we-designed-loki-to-work-easily-both-as-microservices-and-as-monoliths/ [giant-swarm-blog]: https://blog.giantswarm.io/grafana-logging-using-loki [fosdem19-talk]: https://fosdem.org/2019/schedule/event/loki_prometheus_for_logs/ [fosdem19-slides]: https://speakerdeck.com/grafana/grafana-loki-like-prometheus-but-for-logs diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 0000000000000..72c6a9baf8ff7 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,53 @@ +# These may be overwritten by --build-arg to build promtail or debug images +ARG APP=loki +ARG TYPE=production + +# ca-certificates +FROM alpine:3.9 as ssl +RUN apk add --update --no-cache ca-certificates + +# use grafana/loki-build-image to compile binaries +FROM grafana/loki-build-image as golang +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN touch loki-build-image/.uptodate &&\ + mkdir /build + +# production image +FROM golang as builder-production +ARG APP +RUN make BUILD_IN_CONTAINER=false cmd/${APP}/${APP} &&\ + mv cmd/${APP}/${APP} /build/${APP} + +FROM scratch as production +COPY --from=ssl /etc/ssl /etc/ssl +COPY --from=builder-production /build/${APP} /usr/bin/${APP} + +# debug image (only arm64 supported, because of go-delve/delve#118) +FROM golang as builder-debug +ARG APP +RUN go get github.com/go-delve/delve/cmd/dlv &&\ + make BUILD_IN_CONTAINER=false cmd/promtail/promtail-debug &&\ + mv cmd/${APP}/${APP}-debug /build/app-debug &&\ + mv cmd/${APP}/dlv /build/dlv + +FROM alpine:3.9 as debug +COPY --from=ssl /etc/ssl /etc/ssl +COPY --from=builder-debug /build/app-debug /usr/bin/app-debug +COPY --from=builder-debug /build/dlv /usr/bin/dlv +RUN apk add --no-cache libc6-compat +EXPOSE 40000 +ENTRYPOINT ["/usr/bin/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "exec", "/usr/bin/app-debug", "--"] + +# final image with configuration +FROM ${TYPE} as promtail +COPY cmd/promtail/promtail-local-config.yaml cmd/promtail/promtail-docker-config.yaml /etc/promtail/ +ENTRYPOINT ["/usr/bin/promtail"] + +FROM ${TYPE} as loki +COPY cmd/loki/loki-local-config.yaml /etc/loki/local-config.yaml +EXPOSE 80 +ENTRYPOINT ["/usr/bin/loki"] + +FROM ${APP} diff --git a/cmd/docker-driver/Dockerfile b/cmd/docker-driver/Dockerfile new file mode 100644 index 0000000000000..a44c52e38853d --- /dev/null +++ b/cmd/docker-driver/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.9 +RUN apk add --update --no-cache ca-certificates +COPY docker-driver /bin/docker-driver +WORKDIR /bin/ +ENTRYPOINT [ "/bin/docker-driver" ] \ No newline at end of file diff --git a/cmd/docker-driver/README.md b/cmd/docker-driver/README.md new file mode 100644 index 0000000000000..983beabd2733c --- /dev/null +++ b/cmd/docker-driver/README.md @@ -0,0 +1,167 @@ +# Loki Docker Logging Driver + +## Overview + +Docker logging driver plugins extends Docker's logging capabilities. You can use Loki Docker logging driver plugin to send +Docker container logs directly to your Loki instance or [Grafana Cloud](https://grafana.com/loki). + +> Docker plugins are not yet supported on Windows; see Docker's logging driver plugin [documentation](https://docs.docker.com/engine/extend/) + +If you have any questions or issues using the Docker plugin feel free to open an issue in this [repository](https://github.com/grafana/loki/issues). + +## Plugin Installation + +You need to install the plugin on each Docker host with container from which you want to collect logs. + +You can install the plugin from our Docker hub repository by running on the Docker host the following command: + +```bash +docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions +``` + +To check the status of installed plugins, use the `docker plugin ls` command. Plugins that start successfully are listed as enabled in the output: + +```bash +docker plugin ls +ID NAME DESCRIPTION ENABLED +ac720b8fcfdb loki Loki Logging Driver true +``` + +You can now configure the plugin. + +## Plugin Configuration + +The Docker daemon on each Docker host has a default logging driver; each container on the Docker host uses the default driver, unless you configure it to use a different logging driver. + +### Configure the logging driver for a container + +When you start a container, you can configure it to use a different logging driver than the Docker daemon’s default, using the `--log-driver` flag. If the logging driver has configurable options, you can set them using one or more instances of the `--log-opt =` flag. Even if the container uses the default logging driver, it can use different configurable options. + +The following command configure the container `grafana` to start with the loki drivers which will send logs to `logs-us-west1.grafana.net` Loki instance, using a batch size of 400 entries and will retry maximum 5 times if it fails. + +```bash +docker run --log-driver=loki \ + --log-opt loki-url="https://:@logs-us-west1.grafana.net/api/prom/push" \ + --log-opt loki-retries=5 \ + --log-opt loki-batch-size=400 \ + grafana/grafana +``` + +### Configure the default logging driver + +To configure the Docker daemon to default to Loki logging driver, set the value of `log-driver` to `loki` logging driver in the `daemon.json` file, which is located in `/etc/docker/`. The following example explicitly sets the default logging driver to Loki: + +```json +{ + "debug" : true, + "log-driver": "loki" +} +``` + +The logging driver has configurable options, you can set them in the `daemon.json` file as a JSON array with the key log-opts. The following example sets the Loki push endpoint and batch size of the logging driver: + +```json +{ + "debug" : true, + "log-driver": "loki", + "log-opts": { + "loki-url": "https://:@logs-us-west1.grafana.net/api/prom/push", + "loki-batch-size": "400" + } +} +``` + +> **Note**: log-opt configuration options in the daemon.json configuration file must be provided as strings. Boolean and numeric values (such as the value for loki-batch-size in the example above) must therefore be enclosed in quotes ("). + +Restart the Docker daemon and it will be configured with Loki logging driver, all containers from that host will send logs to Loki instance. + +### Configure the logging driver for a Swarm service or Compose + +You can also configure the logging driver for a [swarm service](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/) directly in your compose file, this also work for a docker-compose deployment: + +```yaml +version: "3.7" +services: + logger: + image: grafana/grafana + logging: + driver: loki + options: + loki-url: "https://:@logs-us-west1.grafana.net/api/prom/push" +``` + +You can then deploy your stack using: + +```bash +docker stack deploy my_stack_name --compose-file docker-compose.yaml +``` + +Once deployed the Grafana service will be sending logs automatically to Loki. + +> **Note**: stack name and service name are automatically discovered and sent as Loki labels for each swarm service, this way you can filter by them in Grafana. + +## Labels + +Loki can received a set of labels along with log line. These labels are used to index log entries and query back logs using [LogQL stream selector](../../docs/usage.md#log-stream-selector). + +By default the Docker driver will add the `filename` where the log is written, the `host` where the log has been generated as well as the `container_name`. Additionally `swarm_stack` and `swarm_service` are added for Docker Swarm deployments. + +You can add more labels by using `loki-external-labels`,`loki-pipeline-stage-file`,`labels`,`env` and `env-regex` options as described below. + +## log-opt options + +To specify additional logging driver options, you can use the --log-opt NAME=VALUE flag. + +| Option | Required? | Default Value | Description +| ------------------------- | :-------: | :------------------: | -------------------------------------- | +| `loki-url` | Yes | | Loki HTTP push endpoint. +| `loki-external-labels` | No | `container_name={{.Name}}` | Additional label value pair separated by `,` to send with logs. The value is expanded with the [Docker tag template format](https://docs.docker.com/engine/admin/logging/log_tags/). (eg: `container_name={{.ID}}.{{.Name}},cluster=prod`) +| `loki-timeout` | No | `10s` | The timeout to use when sending logs to the Loki instance. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +| `loki-batch-wait` | No | `1s` | The amount of time to wait before sending a log batch complete or not. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +| `loki-batch-size` | No | `102400` | The maximum size of a log batch to send. +| `loki-min-backoff` | No | `100ms` | The minimum amount of time to wait before retrying a batch. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +| `loki-max-backoff` | No | `10s` | The maximum amount of time to wait before retrying a batch. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +| `loki-retries` | No | `10` | The maximum amount of retries for a log batch. +| `loki-pipeline-stage-file` | No | | The location of a pipeline stage configuration file ([example](./pipeline-example.yaml)). Pipeline stages allows to parse log lines to extract more labels. [see documentation](../../docs/logentry/processing-log-lines.md) +| `loki-tls-ca-file` | No | | Set the path to a custom certificate authority. +| `loki-tls-cert-file` | No | | Set the path to a client certificate file. +| `loki-tls-key-file` | No | | Set the path to a client key. +| `loki-tls-server-name` | No | | Name used to validate the server certificate. +| `loki-tls-insecure-skip-verify` | No | `false` | Allow to skip tls verification. +| `loki-proxy-url` | No | | Proxy URL use to connect to Loki. +| `labels` | No | | Comma-separated list of keys of labels, which should be included in message, if these labels are specified for container. +| `env` | No | | Comma-separated list of keys of environment variables to be included in message if they specified for a container. +| `env-regex` | No | | A regular expression to match logging-related environment variables. Used for advanced log label options. If there is collision between the label and env keys, the value of the env takes precedence. Both options add additional fields to the labels of a logging message. + +## Uninstall the plugin + +To cleanly disable and remove the plugin, run: + +```bash +docker plugin disable loki +docker plugin rm loki +``` + +## Upgrade the plugin + +To upgrade the plugin to the last version, run: + +```bash +docker plugin disable loki +docker plugin upgrade loki grafana/loki-docker-driver:master +docker plugin enable loki +``` + +## Troubleshooting + +Plugin logs can be found as docker daemon log. To enable debug mode refer to the Docker daemon documentation: https://docs.docker.com/config/daemon/ + +Stdout of a plugin is redirected to Docker logs. Such entries have a plugin= suffix. + +To find out the plugin ID of Loki, use the command below and look for Loki plugin entry. + +```bash +docker plugin ls +``` + +Depending on your system, location of Docker daemon logging may vary. Refer to Docker documentation for Docker daemon log location for your specific platform. ([see](https://docs.docker.com/config/daemon/)) diff --git a/cmd/docker-driver/config.go b/cmd/docker-driver/config.go new file mode 100644 index 0000000000000..e8efaa8dab9ac --- /dev/null +++ b/cmd/docker-driver/config.go @@ -0,0 +1,296 @@ +package main + +import ( + "bytes" + "fmt" + "net/url" + "os" + "strconv" + "strings" + "time" + + "github.com/cortexproject/cortex/pkg/util" + "github.com/cortexproject/cortex/pkg/util/flagext" + "github.com/docker/docker/daemon/logger" + "github.com/docker/docker/daemon/logger/templates" + "github.com/grafana/loki/pkg/helpers" + "github.com/grafana/loki/pkg/logentry/stages" + "github.com/grafana/loki/pkg/promtail/client" + "github.com/grafana/loki/pkg/promtail/targets" + "github.com/prometheus/common/model" +) + +const ( + driverName = "loki" + + cfgExternalLabelsKey = "loki-external-labels" + cfgURLKey = "loki-url" + cfgTLSCAFileKey = "loki-tls-ca-file" + cfgTLSCertFileKey = "loki-tls-cert-file" + cfgTLSKeyFileKey = "loki-tls-key-file" + cfgTLSServerNameKey = "loki-tls-server-name" + cfgTLSInsecure = "loki-tls-insecure-skip-verify" + cfgProxyURLKey = "loki-proxy-url" + cfgTimeoutKey = "loki-timeout" + cfgBatchWaitKey = "loki-batch-wait" + cfgBatchSizeKey = "loki-batch-size" + cfgMinBackoffKey = "loki-min-backoff" + cfgMaxBackoffKey = "loki-max-backoff" + cfgMaxRetriesKey = "loki-retries" + cfgPipelineStagesKey = "loki-pipeline-stage-file" + + swarmServiceLabelKey = "com.docker.swarm.service.name" + swarmStackLabelKey = "com.docker.stack.namespace" + + swarmServiceLabelName = "swarm_service" + swarmStackLabelName = "swarm_stack" + + defaultExternalLabels = "container_name={{.Name}}" + defaultHostLabelName = model.LabelName("host") +) + +var ( + defaultClientConfig = client.Config{ + BatchWait: 1 * time.Second, + BatchSize: 100 * 1024, + BackoffConfig: util.BackoffConfig{ + MinBackoff: 100 * time.Millisecond, + MaxBackoff: 10 * time.Second, + MaxRetries: 10, + }, + Timeout: 10 * time.Second, + } +) + +type config struct { + labels model.LabelSet + clientConfig client.Config + pipeline PipelineConfig +} + +type PipelineConfig struct { + PipelineStages stages.PipelineStages `yaml:"pipeline_stages,omitempty"` +} + +func validateDriverOpt(loggerInfo logger.Info) error { + config := loggerInfo.Config + + for opt := range config { + switch opt { + case cfgURLKey: + case cfgExternalLabelsKey: + case cfgTLSCAFileKey: + case cfgTLSCertFileKey: + case cfgTLSKeyFileKey: + case cfgTLSServerNameKey: + case cfgTLSInsecure: + case cfgTimeoutKey: + case cfgProxyURLKey: + case cfgBatchWaitKey: + case cfgBatchSizeKey: + case cfgMinBackoffKey: + case cfgMaxBackoffKey: + case cfgMaxRetriesKey: + case cfgPipelineStagesKey: + case "labels": + case "env": + case "env-regex": + default: + return fmt.Errorf("%s: wrong log-opt: '%s' - %s", driverName, opt, loggerInfo.ContainerID) + } + } + _, ok := config[cfgURLKey] + if !ok { + return fmt.Errorf("%s: %s is required in the config", driverName, cfgURLKey) + } + + return nil +} + +func parseConfig(logCtx logger.Info) (*config, error) { + if err := validateDriverOpt(logCtx); err != nil { + return nil, err + } + + clientConfig := defaultClientConfig + labels := model.LabelSet{} + + // parse URL + rawURL, ok := logCtx.Config[cfgURLKey] + if !ok { + return nil, fmt.Errorf("%s: option %s is required", driverName, cfgURLKey) + } + url, err := url.Parse(rawURL) + if err != nil { + return nil, fmt.Errorf("%s: option %s is invalid %s", driverName, cfgURLKey, err) + } + clientConfig.URL = flagext.URLValue{URL: url} + + // parse timeout + if err := parseDuration(cfgTimeoutKey, logCtx, func(d time.Duration) { clientConfig.Timeout = d }); err != nil { + return nil, err + } + + // parse batch wait and batch size + if err := parseDuration(cfgBatchWaitKey, logCtx, func(d time.Duration) { clientConfig.BatchWait = d }); err != nil { + return nil, err + } + if err := parseInt(cfgBatchSizeKey, logCtx, func(i int) { clientConfig.BatchSize = i }); err != nil { + return nil, err + } + + // parse backoff + if err := parseDuration(cfgMinBackoffKey, logCtx, func(d time.Duration) { clientConfig.BackoffConfig.MinBackoff = d }); err != nil { + return nil, err + } + if err := parseDuration(cfgMaxBackoffKey, logCtx, func(d time.Duration) { clientConfig.BackoffConfig.MaxBackoff = d }); err != nil { + return nil, err + } + if err := parseInt(cfgMaxRetriesKey, logCtx, func(i int) { clientConfig.BackoffConfig.MaxRetries = i }); err != nil { + return nil, err + } + + // parse http & tls config + if tlsCAFile, ok := logCtx.Config[cfgTLSCAFileKey]; ok { + clientConfig.Client.TLSConfig.CAFile = tlsCAFile + } + if tlsCertFile, ok := logCtx.Config[cfgTLSCertFileKey]; ok { + clientConfig.Client.TLSConfig.CertFile = tlsCertFile + } + if tlsCertFile, ok := logCtx.Config[cfgTLSCertFileKey]; ok { + clientConfig.Client.TLSConfig.CertFile = tlsCertFile + } + if tlsKeyFile, ok := logCtx.Config[cfgTLSKeyFileKey]; ok { + clientConfig.Client.TLSConfig.KeyFile = tlsKeyFile + } + if tlsServerName, ok := logCtx.Config[cfgTLSServerNameKey]; ok { + clientConfig.Client.TLSConfig.ServerName = tlsServerName + } + if tlsInsecureSkipRaw, ok := logCtx.Config[cfgTLSInsecure]; ok { + tlsInsecureSkip, err := strconv.ParseBool(tlsInsecureSkipRaw) + if err != nil { + return nil, fmt.Errorf("%s: invalid external labels: %s", driverName, tlsInsecureSkipRaw) + } + clientConfig.Client.TLSConfig.InsecureSkipVerify = tlsInsecureSkip + } + if tlsProxyURL, ok := logCtx.Config[cfgProxyURLKey]; ok { + proxyURL, err := url.Parse(tlsProxyURL) + if err != nil { + return nil, fmt.Errorf("%s: option %s is invalid %s", driverName, cfgProxyURLKey, err) + } + clientConfig.Client.ProxyURL.URL = proxyURL + } + + // parse external labels + extlbs, ok := logCtx.Config[cfgExternalLabelsKey] + if !ok { + extlbs = defaultExternalLabels + } + lvs := strings.Split(extlbs, ",") + for _, lv := range lvs { + lvparts := strings.Split(lv, "=") + if len(lvparts) != 2 { + return nil, fmt.Errorf("%s: invalid external labels: %s", driverName, extlbs) + } + labelName := model.LabelName(lvparts[0]) + if !labelName.IsValid() { + return nil, fmt.Errorf("%s: invalid external label name: %s", driverName, labelName) + } + + // expand the value using docker template {{.Name}}.{{.ImageName}} + value, err := expandLabelValue(logCtx, lvparts[1]) + if err != nil { + return nil, fmt.Errorf("%s: could not expand label value: %s err : %s", driverName, lvparts[1], err) + } + labelValue := model.LabelValue(value) + if !labelValue.IsValid() { + return nil, fmt.Errorf("%s: invalid external label value: %s", driverName, value) + } + labels[labelName] = labelValue + } + + // other labels coming from docker labels or env selected by user labels, labels-regex, env, env-regex config. + attrs, err := logCtx.ExtraAttributes(nil) + if err != nil { + return nil, err + } + + // parse docker swarms labels and adds them automatically to attrs + swarmService := logCtx.ContainerLabels[swarmServiceLabelKey] + if swarmService != "" { + attrs[swarmServiceLabelName] = swarmService + } + swarmStack := logCtx.ContainerLabels[swarmStackLabelKey] + if swarmStack != "" { + attrs[swarmStackLabelName] = swarmStack + } + + for key, value := range attrs { + labelName := model.LabelName(key) + if !labelName.IsValid() { + return nil, fmt.Errorf("%s: invalid label name from attribute: %s", driverName, key) + } + labelValue := model.LabelValue(value) + if !labelValue.IsValid() { + return nil, fmt.Errorf("%s: invalid label value from attribute: %s", driverName, value) + } + labels[labelName] = labelValue + } + + // adds host label and filename + host, err := os.Hostname() + if err == nil { + labels[defaultHostLabelName] = model.LabelValue(host) + } + labels[targets.FilenameLabel] = model.LabelValue(logCtx.LogPath) + + // parse pipeline stages + var pipeline PipelineConfig + pipelineFile, ok := logCtx.Config[cfgPipelineStagesKey] + if ok { + if err := helpers.LoadConfig(pipelineFile, &pipeline); err != nil { + return nil, fmt.Errorf("%s: error loading config file %s: %s", driverName, pipelineFile, err) + } + } + + return &config{ + labels: labels, + clientConfig: clientConfig, + pipeline: pipeline, + }, nil +} + +func expandLabelValue(info logger.Info, defaultTemplate string) (string, error) { + tmpl, err := templates.NewParse("label_value", defaultTemplate) + if err != nil { + return "", err + } + buf := new(bytes.Buffer) + if err := tmpl.Execute(buf, &info); err != nil { + return "", err + } + + return buf.String(), nil +} + +func parseDuration(key string, logCtx logger.Info, set func(d time.Duration)) error { + if raw, ok := logCtx.Config[key]; ok { + val, err := time.ParseDuration(raw) + if err != nil { + return fmt.Errorf("%s: invalid option %s format: %s", driverName, key, raw) + } + set(val) + } + return nil +} + +func parseInt(key string, logCtx logger.Info, set func(i int)) error { + if raw, ok := logCtx.Config[key]; ok { + val, err := strconv.Atoi(raw) + if err != nil { + return fmt.Errorf("%s: invalid option %s format: %s", driverName, key, raw) + } + set(val) + } + return nil +} diff --git a/cmd/docker-driver/config.json b/cmd/docker-driver/config.json new file mode 100644 index 0000000000000..7216230404401 --- /dev/null +++ b/cmd/docker-driver/config.json @@ -0,0 +1,20 @@ +{ + "description": "Loki Logging Driver", + "documentation": "https://github.com/grafana/loki", + "entrypoint": ["/bin/docker-driver"], + "network": { + "type": "host" + }, + "interface": { + "types": ["docker.logdriver/1.0"], + "socket": "loki.sock" + }, + "env": [ + { + "name": "LOG_LEVEL", + "description": "Set log level to output for plugin logs", + "value": "info", + "settable": ["value"] + } + ] +} \ No newline at end of file diff --git a/cmd/docker-driver/driver.go b/cmd/docker-driver/driver.go new file mode 100644 index 0000000000000..f99e5c33412fa --- /dev/null +++ b/cmd/docker-driver/driver.go @@ -0,0 +1,200 @@ +package main + +import ( + "context" + "encoding/binary" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "syscall" + "time" + + "github.com/docker/docker/api/types/backend" + "github.com/docker/docker/api/types/plugins/logdriver" + "github.com/docker/docker/daemon/logger" + "github.com/docker/docker/daemon/logger/jsonfilelog" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + protoio "github.com/gogo/protobuf/io" + "github.com/pkg/errors" + "github.com/tonistiigi/fifo" +) + +type driver struct { + mu sync.Mutex + logs map[string]*logPair + idx map[string]*logPair + logger log.Logger +} + +type logPair struct { + jsonl logger.Logger + lokil logger.Logger + stream io.ReadCloser + info logger.Info + logger log.Logger +} + +func (l *logPair) Close() { + if err := l.stream.Close(); err != nil { + level.Error(l.logger).Log("msg", "error while closing fifo stream", "err", err) + } + if err := l.lokil.Close(); err != nil { + level.Error(l.logger).Log("msg", "error while closing loki logger", "err", err) + } + if err := l.jsonl.Close(); err != nil { + level.Error(l.logger).Log("msg", "error while closing json logger", "err", err) + } +} + +func newDriver(logger log.Logger) *driver { + return &driver{ + logs: make(map[string]*logPair), + idx: make(map[string]*logPair), + logger: logger, + } +} + +func (d *driver) StartLogging(file string, logCtx logger.Info) error { + d.mu.Lock() + if _, exists := d.logs[file]; exists { + d.mu.Unlock() + return fmt.Errorf("logger for %q already exists", file) + } + d.mu.Unlock() + + if logCtx.LogPath == "" { + logCtx.LogPath = filepath.Join("/var/log/docker", logCtx.ContainerID) + } + if err := os.MkdirAll(filepath.Dir(logCtx.LogPath), 0755); err != nil { + return errors.Wrap(err, "error setting up logger dir") + } + jsonl, err := jsonfilelog.New(logCtx) + if err != nil { + return errors.Wrap(err, "error creating jsonfile logger") + } + + lokil, err := New(logCtx, d.logger) + if err != nil { + return errors.Wrap(err, "error creating loki logger") + } + level.Debug(d.logger).Log("msg", "Start logging", "id", logCtx.ContainerID, "file", file, "logpath", logCtx.LogPath) + f, err := fifo.OpenFifo(context.Background(), file, syscall.O_RDONLY, 0700) + if err != nil { + return errors.Wrapf(err, "error opening logger fifo: %q", file) + } + + d.mu.Lock() + lf := &logPair{jsonl, lokil, f, logCtx, d.logger} + d.logs[file] = lf + d.idx[logCtx.ContainerID] = lf + d.mu.Unlock() + + go consumeLog(lf) + return nil +} + +func (d *driver) StopLogging(file string) { + level.Debug(d.logger).Log("msg", "Stop logging", "file", file) + d.mu.Lock() + lf, ok := d.logs[file] + if ok { + lf.Close() + delete(d.logs, file) + } + d.mu.Unlock() +} + +func consumeLog(lf *logPair) { + dec := protoio.NewUint32DelimitedReader(lf.stream, binary.BigEndian, 1e6) + defer dec.Close() + defer lf.Close() + var buf logdriver.LogEntry + for { + if err := dec.ReadMsg(&buf); err != nil { + if err == io.EOF || err == os.ErrClosed || strings.Contains(err.Error(), "file already closed") { + level.Debug(lf.logger).Log("msg", "shutting down log logger", "id", lf.info.ContainerID, "err", err) + return + } + dec = protoio.NewUint32DelimitedReader(lf.stream, binary.BigEndian, 1e6) + } + var msg logger.Message + msg.Line = buf.Line + msg.Source = buf.Source + if buf.PartialLogMetadata != nil { + if msg.PLogMetaData == nil { + msg.PLogMetaData = &backend.PartialLogMetaData{} + } + msg.PLogMetaData.ID = buf.PartialLogMetadata.Id + msg.PLogMetaData.Last = buf.PartialLogMetadata.Last + msg.PLogMetaData.Ordinal = int(buf.PartialLogMetadata.Ordinal) + } + msg.Timestamp = time.Unix(0, buf.TimeNano) + + // loki goes first as the json logger reset the message on completion. + if err := lf.lokil.Log(&msg); err != nil { + level.Error(lf.logger).Log("msg", "error pushing message to loki", "id", lf.info.ContainerID, "err", err, "message", msg) + } + + if err := lf.jsonl.Log(&msg); err != nil { + level.Error(lf.logger).Log("msg", "error writing log message", "id", lf.info.ContainerID, "err", err, "message", msg) + continue + } + + buf.Reset() + } +} + +func (d *driver) ReadLogs(info logger.Info, config logger.ReadConfig) (io.ReadCloser, error) { + d.mu.Lock() + lf, exists := d.idx[info.ContainerID] + d.mu.Unlock() + if !exists { + return nil, fmt.Errorf("logger does not exist for %s", info.ContainerID) + } + + r, w := io.Pipe() + lr, ok := lf.jsonl.(logger.LogReader) + if !ok { + return nil, fmt.Errorf("logger does not support reading") + } + + go func() { + watcher := lr.ReadLogs(config) + + enc := protoio.NewUint32DelimitedWriter(w, binary.BigEndian) + defer enc.Close() + defer watcher.ConsumerGone() + + var buf logdriver.LogEntry + for { + select { + case msg, ok := <-watcher.Msg: + if !ok { + w.Close() + return + } + + buf.Line = msg.Line + buf.Partial = msg.PLogMetaData != nil + buf.TimeNano = msg.Timestamp.UnixNano() + buf.Source = msg.Source + + if err := enc.WriteMsg(&buf); err != nil { + _ = w.CloseWithError(err) + return + } + case err := <-watcher.Err: + _ = w.CloseWithError(err) + return + } + + buf.Reset() + } + }() + + return r, nil +} diff --git a/cmd/docker-driver/http.go b/cmd/docker-driver/http.go new file mode 100644 index 0000000000000..5045e2c9d1c41 --- /dev/null +++ b/cmd/docker-driver/http.go @@ -0,0 +1,95 @@ +package main + +import ( + "encoding/json" + "errors" + "io" + "net/http" + + "github.com/docker/docker/daemon/logger" + "github.com/docker/docker/pkg/ioutils" + "github.com/docker/go-plugins-helpers/sdk" +) + +type StartLoggingRequest struct { + File string + Info logger.Info +} + +type StopLoggingRequest struct { + File string +} + +type CapabilitiesResponse struct { + Err string + Cap logger.Capability +} + +type ReadLogsRequest struct { + Info logger.Info + Config logger.ReadConfig +} + +func handlers(h *sdk.Handler, d *driver) { + h.HandleFunc("/LogDriver.StartLogging", func(w http.ResponseWriter, r *http.Request) { + var req StartLoggingRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if req.Info.ContainerID == "" { + respond(errors.New("must provide container id in log context"), w) + return + } + + err := d.StartLogging(req.File, req.Info) + respond(err, w) + }) + + h.HandleFunc("/LogDriver.StopLogging", func(w http.ResponseWriter, r *http.Request) { + var req StopLoggingRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + d.StopLogging(req.File) + respond(nil, w) + }) + + h.HandleFunc("/LogDriver.Capabilities", func(w http.ResponseWriter, r *http.Request) { + _ = json.NewEncoder(w).Encode(&CapabilitiesResponse{ + Cap: logger.Capability{ReadLogs: true}, + }) + }) + + h.HandleFunc("/LogDriver.ReadLogs", func(w http.ResponseWriter, r *http.Request) { + var req ReadLogsRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + stream, err := d.ReadLogs(req.Info, req.Config) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer stream.Close() + + w.Header().Set("Content-Type", "application/x-json-stream") + wf := ioutils.NewWriteFlusher(w) + _, _ = io.Copy(wf, stream) + }) +} + +type response struct { + Err string +} + +func respond(err error, w io.Writer) { + var res response + if err != nil { + res.Err = err.Error() + } + _ = json.NewEncoder(w).Encode(&res) +} diff --git a/cmd/docker-driver/loki.go b/cmd/docker-driver/loki.go new file mode 100644 index 0000000000000..e8d99cea5862f --- /dev/null +++ b/cmd/docker-driver/loki.go @@ -0,0 +1,70 @@ +package main + +import ( + "bytes" + + "github.com/docker/docker/daemon/logger" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + "github.com/grafana/loki/pkg/logentry/stages" + "github.com/grafana/loki/pkg/promtail/api" + "github.com/grafana/loki/pkg/promtail/client" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" +) + +var jobName = "docker" + +type loki struct { + client client.Client + handler api.EntryHandler + labels model.LabelSet + logger log.Logger +} + +// New create a new Loki logger that forward logs to Loki instance +func New(logCtx logger.Info, logger log.Logger) (logger.Logger, error) { + logger = log.With(logger, "container_id", logCtx.ContainerID) + cfg, err := parseConfig(logCtx) + if err != nil { + return nil, err + } + c, err := client.New(cfg.clientConfig, logger) + if err != nil { + return nil, err + } + var handler api.EntryHandler = c + if len(cfg.pipeline.PipelineStages) != 0 { + pipeline, err := stages.NewPipeline(logger, cfg.pipeline.PipelineStages, &jobName, prometheus.DefaultRegisterer) + if err != nil { + return nil, err + } + handler = pipeline.Wrap(c) + } + return &loki{ + client: c, + labels: cfg.labels, + logger: logger, + handler: handler, + }, nil +} + +// Log implements `logger.Logger` +func (l *loki) Log(m *logger.Message) error { + if len(bytes.Fields(m.Line)) == 0 { + level.Info(l.logger).Log("msg", "ignoring empty line", "line", string(m.Line)) + return nil + } + return l.handler.Handle(l.labels.Clone(), m.Timestamp, string(m.Line)) +} + +// Log implements `logger.Logger` +func (l *loki) Name() string { + return driverName +} + +// Log implements `logger.Logger` +func (l *loki) Close() error { + l.client.Stop() + return nil +} diff --git a/cmd/docker-driver/main.go b/cmd/docker-driver/main.go new file mode 100644 index 0000000000000..1598998f7e8c0 --- /dev/null +++ b/cmd/docker-driver/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "os" + + "github.com/cortexproject/cortex/pkg/util" + "github.com/docker/go-plugins-helpers/sdk" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + "github.com/prometheus/common/version" + "github.com/weaveworks/common/logging" +) + +const socketAddress = "/run/docker/plugins/loki.sock" + +var logLevel logging.Level + +func main() { + levelVal := os.Getenv("LOG_LEVEL") + if levelVal == "" { + levelVal = "info" + } + + if err := logLevel.Set(levelVal); err != nil { + fmt.Fprintln(os.Stdout, "invalid log level: ", levelVal) + os.Exit(1) + } + logger := newLogger(logLevel) + level.Info(util.Logger).Log("msg", "Starting docker-plugin", "version", version.Info()) + h := sdk.NewHandler(`{"Implements": ["LoggingDriver"]}`) + handlers(&h, newDriver(logger)) + if err := h.ServeUnix(socketAddress, 0); err != nil { + panic(err) + } + +} + +func newLogger(lvl logging.Level) log.Logger { + // plugin logs must be stdout to appear. + logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)) + logger = level.NewFilter(logger, lvl.Gokit) + logger = log.With(logger, "ts", log.DefaultTimestampUTC) + logger = log.With(logger, "caller", log.Caller(3)) + return logger +} diff --git a/cmd/docker-driver/pipeline-example.yaml b/cmd/docker-driver/pipeline-example.yaml new file mode 100644 index 0000000000000..91310d7974826 --- /dev/null +++ b/cmd/docker-driver/pipeline-example.yaml @@ -0,0 +1,5 @@ +pipeline_stages: +- regex: + expression: '(level|lvl|severity)=(?P\\w+)' +- labels: + level: \ No newline at end of file diff --git a/cmd/logcli/client.go b/cmd/logcli/client.go index 3acaea6b65eea..0984ba4538993 100644 --- a/cmd/logcli/client.go +++ b/cmd/logcli/client.go @@ -12,6 +12,7 @@ import ( "time" "github.com/gorilla/websocket" + "github.com/prometheus/common/config" "github.com/grafana/loki/pkg/logproto" ) @@ -20,12 +21,18 @@ const ( queryPath = "/api/prom/query?query=%s&limit=%d&start=%d&end=%d&direction=%s®exp=%s" labelsPath = "/api/prom/label" labelValuesPath = "/api/prom/label/%s/values" - tailPath = "/api/prom/tail?query=%s®exp=%s" + tailPath = "/api/prom/tail?query=%s®exp=%s&delay_for=%d&limit=%d&start=%d" ) func query(from, through time.Time, direction logproto.Direction) (*logproto.QueryResponse, error) { - path := fmt.Sprintf(queryPath, url.QueryEscape(*queryStr), *limit, from.UnixNano(), - through.UnixNano(), direction.String(), url.QueryEscape(*regexpStr)) + path := fmt.Sprintf(queryPath, + url.QueryEscape(*queryStr), // query + *limit, // limit + from.UnixNano(), // start + through.UnixNano(), // end + direction.String(), // direction + url.QueryEscape(*regexpStr), // regexp + ) var resp logproto.QueryResponse if err := doRequest(path, &resp); err != nil { @@ -53,22 +60,45 @@ func listLabelValues(name string) (*logproto.LabelResponse, error) { } func doRequest(path string, out interface{}) error { - url := *addr + path - log.Print(url) + us := *addr + path + if !*quiet { + log.Print(us) + } - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest("GET", us, nil) if err != nil { return err } + req.SetBasicAuth(*username, *password) - resp, err := http.DefaultClient.Do(req) + // Parse the URL to extract the host + u, err := url.Parse(us) + if err != nil { + return err + } + clientConfig := config.HTTPClientConfig{ + TLSConfig: config.TLSConfig{ + CAFile: *tlsCACertPath, + CertFile: *tlsClientCertPath, + KeyFile: *tlsClientCertKeyPath, + ServerName: u.Host, + InsecureSkipVerify: *tlsSkipVerify, + }, + } + + client, err := config.NewClientFromConfig(clientConfig, "logcli") + if err != nil { + return err + } + + resp, err := client.Do(req) if err != nil { return err } defer func() { if err := resp.Body.Close(); err != nil { - fmt.Println("error closing body", err) + log.Println("error closing body", err) } }() @@ -81,21 +111,51 @@ func doRequest(path string, out interface{}) error { } func liveTailQueryConn() (*websocket.Conn, error) { - path := fmt.Sprintf(tailPath, url.QueryEscape(*queryStr), url.QueryEscape(*regexpStr)) + path := fmt.Sprintf(tailPath, + url.QueryEscape(*queryStr), // query + url.QueryEscape(*regexpStr), // regexp + *delayFor, // delay_for + *limit, // limit + getStart(time.Now()).UnixNano(), // start + ) return wsConnect(path) } func wsConnect(path string) (*websocket.Conn, error) { - url := *addr + path - if strings.HasPrefix(url, "https") { - url = strings.Replace(url, "https", "wss", 1) - } else if strings.HasPrefix(url, "http") { - url = strings.Replace(url, "http", "ws", 1) + us := *addr + path + + // Parse the URL to extract the host + u, err := url.Parse(us) + if err != nil { + return nil, err + } + tlsConfig, err := config.NewTLSConfig(&config.TLSConfig{ + CAFile: *tlsCACertPath, + CertFile: *tlsClientCertPath, + KeyFile: *tlsClientCertKeyPath, + ServerName: u.Host, + InsecureSkipVerify: *tlsSkipVerify, + }) + if err != nil { + return nil, err + } + + if strings.HasPrefix(us, "https") { + us = strings.Replace(us, "https", "wss", 1) + } else if strings.HasPrefix(us, "http") { + us = strings.Replace(us, "http", "ws", 1) + } + if !*quiet { + log.Println(us) } - fmt.Println(url) h := http.Header{"Authorization": {"Basic " + base64.StdEncoding.EncodeToString([]byte(*username+":"+*password))}} - c, resp, err := websocket.DefaultDialer.Dial(url, h) + + ws := websocket.Dialer{ + TLSClientConfig: tlsConfig, + } + + c, resp, err := ws.Dial(us, h) if err != nil { if resp == nil { diff --git a/cmd/logcli/main.go b/cmd/logcli/main.go index 596bdda6f0f0e..38ce7791f7938 100644 --- a/cmd/logcli/main.go +++ b/cmd/logcli/main.go @@ -4,37 +4,53 @@ import ( "log" "os" - kingpin "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/alecthomas/kingpin.v2" ) var ( - app = kingpin.New("logcli", "A command-line for loki.") + app = kingpin.New("logcli", "A command-line for loki.") + quiet = app.Flag("quiet", "suppress everything but log lines").Default("false").Short('q').Bool() + outputMode = app.Flag("output", "specify output mode [default, raw, jsonl]").Default("default").Short('o').Enum("default", "raw", "jsonl") + + addr = app.Flag("addr", "Server address.").Default("https://logs-us-west1.grafana.net").Envar("GRAFANA_ADDR").String() - addr = app.Flag("addr", "Server address.").Default("https://logs-us-west1.grafana.net").Envar("GRAFANA_ADDR").String() username = app.Flag("username", "Username for HTTP basic auth.").Default("").Envar("GRAFANA_USERNAME").String() password = app.Flag("password", "Password for HTTP basic auth.").Default("").Envar("GRAFANA_PASSWORD").String() - queryCmd = app.Command("query", "Run a LogQL query.") - queryStr = queryCmd.Arg("query", "eg '{foo=\"bar\",baz=\"blip\"}'").Required().String() - regexpStr = queryCmd.Arg("regex", "").String() - limit = queryCmd.Flag("limit", "Limit on number of entries to print.").Default("30").Int() - since = queryCmd.Flag("since", "Lookback window.").Default("1h").Duration() - forward = queryCmd.Flag("forward", "Scan forwards through logs.").Default("false").Bool() - tail = queryCmd.Flag("tail", "Tail the logs").Short('t').Default("false").Bool() - noLabels = queryCmd.Flag("no-labels", "Do not print labels").Default("false").Bool() - - labelsCmd = app.Command("labels", "Find values for a given label.") - labelName = labelsCmd.Arg("label", "The name of the label.").HintAction(listLabels).String() + tlsCACertPath = app.Flag("ca-cert", "Path to the server Certificate Authority.").Default("").Envar("LOKI_CA_CERT_PATH").String() + tlsSkipVerify = app.Flag("tls-skip-verify", "Server certificate TLS skip verify.").Default("false").Bool() + tlsClientCertPath = app.Flag("cert", "Path to the client certificate.").Default("").Envar("LOKI_CLIENT_CERT_PATH").String() + tlsClientCertKeyPath = app.Flag("key", "Path to the client certificate key.").Default("").Envar("LOKI_CLIENT_KEY_PATH").String() + + queryCmd = app.Command("query", "Run a LogQL query.") + queryStr = queryCmd.Arg("query", "eg '{foo=\"bar\",baz=\"blip\"}'").Required().String() + regexpStr = queryCmd.Arg("regex", "").String() + limit = queryCmd.Flag("limit", "Limit on number of entries to print.").Default("30").Int() + since = queryCmd.Flag("since", "Lookback window.").Default("1h").Duration() + from = queryCmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").String() + to = queryCmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").String() + forward = queryCmd.Flag("forward", "Scan forwards through logs.").Default("false").Bool() + tail = queryCmd.Flag("tail", "Tail the logs").Short('t').Default("false").Bool() + delayFor = queryCmd.Flag("delay-for", "Delay in tailing by number of seconds to accumulate logs for re-ordering").Default("0").Int() + noLabels = queryCmd.Flag("no-labels", "Do not print any labels").Default("false").Bool() + ignoreLabelsKey = queryCmd.Flag("exclude-label", "Exclude labels given the provided key during output.").Strings() + showLabelsKey = queryCmd.Flag("include-label", "Include labels given the provided key during output.").Strings() + fixedLabelsLen = queryCmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").Int() + labelsCmd = app.Command("labels", "Find values for a given label.") + labelName = labelsCmd.Arg("label", "The name of the label.").HintAction(listLabels).String() ) func main() { log.SetOutput(os.Stderr) - switch kingpin.MustParse(app.Parse(os.Args[1:])) { + cmd := kingpin.MustParse(app.Parse(os.Args[1:])) + + if *addr == "" { + log.Fatalln("Server address cannot be empty") + } + + switch cmd { case queryCmd.FullCommand(): - if *addr == "" { - log.Fatalln("Server address cannot be empty") - } doQuery() case labelsCmd.FullCommand(): doLabels() diff --git a/cmd/logcli/output.go b/cmd/logcli/output.go new file mode 100644 index 0000000000000..d822775058f21 --- /dev/null +++ b/cmd/logcli/output.go @@ -0,0 +1,73 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "strings" + "time" + + "github.com/fatih/color" + "github.com/prometheus/prometheus/pkg/labels" +) + +// Outputs is an enum with all possible output modes +var Outputs = map[string]LogOutput{ + "default": &DefaultOutput{}, + "jsonl": &JSONLOutput{}, + "raw": &RawOutput{}, +} + +// LogOutput is the interface any output mode must implement +type LogOutput interface { + Print(ts time.Time, lbls *labels.Labels, line string) +} + +// DefaultOutput provides logs and metadata in human readable format +type DefaultOutput struct { + MaxLabelsLen int + CommonLabels labels.Labels +} + +// Print a log entry in a human readable format +func (f DefaultOutput) Print(ts time.Time, lbls *labels.Labels, line string) { + ls := subtract(*lbls, f.CommonLabels) + if len(*ignoreLabelsKey) > 0 { + ls = ls.MatchLabels(false, *ignoreLabelsKey...) + } + + labels := "" + if !*noLabels { + labels = padLabel(ls, f.MaxLabelsLen) + } + fmt.Println( + color.BlueString(ts.Format(time.RFC3339)), + color.RedString(labels), + strings.TrimSpace(line), + ) +} + +// JSONLOutput prints logs and metadata as JSON Lines, suitable for scripts +type JSONLOutput struct{} + +// Print a log entry as json line +func (f JSONLOutput) Print(ts time.Time, lbls *labels.Labels, line string) { + entry := map[string]interface{}{ + "timestamp": ts, + "labels": lbls, + "line": line, + } + out, err := json.Marshal(entry) + if err != nil { + log.Fatalf("error marshalling entry: %s", err) + } + fmt.Println(string(out)) +} + +// RawOutput prints logs in their original form, without any metadata +type RawOutput struct{} + +// Print a log entry as is +func (f RawOutput) Print(ts time.Time, lbls *labels.Labels, line string) { + fmt.Println(line) +} diff --git a/cmd/logcli/query.go b/cmd/logcli/query.go index 4a7b47f0d0346..735527ea40c97 100644 --- a/cmd/logcli/query.go +++ b/cmd/logcli/query.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "log" "strings" "time" @@ -11,9 +10,20 @@ import ( "github.com/grafana/loki/pkg/iter" "github.com/grafana/loki/pkg/logproto" - "github.com/grafana/loki/pkg/parser" ) +func getStart(end time.Time) time.Time { + start := end.Add(-*since) + if *from != "" { + var err error + start, err = time.Parse(time.RFC3339Nano, *from) + if err != nil { + log.Fatalf("error parsing date '%s': %s", *from, err) + } + } + return start +} + func doQuery() { if *tail { tailQuery() @@ -21,13 +31,21 @@ func doQuery() { } var ( - i iter.EntryIterator - common labels.Labels - maxLabelsLen = 100 + i iter.EntryIterator + common labels.Labels ) end := time.Now() - start := end.Add(-*since) + start := getStart(end) + + if *to != "" { + var err error + end, err = time.Parse(time.RFC3339Nano, *to) + if err != nil { + log.Fatalf("error parsing --to date '%s': %s", *to, err) + } + } + d := logproto.BACKWARD if *forward { d = logproto.FORWARD @@ -43,126 +61,48 @@ func doQuery() { labelsCache := func(labels string) labels.Labels { return cache[labels] } + common = commonLabels(lss) - i = iter.NewQueryResponseIterator(resp, d) - if len(common) > 0 { - fmt.Println("Common labels:", color.RedString(common.String())) + // Remove the labels we want to show from common + if len(*showLabelsKey) > 0 { + common = common.MatchLabels(false, *showLabelsKey...) + } + + if len(common) > 0 && !*quiet { + log.Println("Common labels:", color.RedString(common.String())) + } + + if len(*ignoreLabelsKey) > 0 && !*quiet { + log.Println("Ignoring labels key:", color.RedString(strings.Join(*ignoreLabelsKey, ","))) } + // Get the max size of labels + maxLabelsLen := *fixedLabelsLen for _, ls := range cache { ls = subtract(common, ls) + if len(*ignoreLabelsKey) > 0 { + ls = ls.MatchLabels(false, *ignoreLabelsKey...) + } len := len(ls.String()) if maxLabelsLen < len { maxLabelsLen = len } } - for i.Next() { - ls := labelsCache(i.Labels()) - ls = subtract(ls, common) + i = iter.NewQueryResponseIterator(resp, d) - labels := "" - if !*noLabels { - labels = padLabel(ls, maxLabelsLen) - } + Outputs["default"] = DefaultOutput{ + MaxLabelsLen: maxLabelsLen, + CommonLabels: common, + } - printLogEntry(i.Entry().Timestamp, labels, i.Entry().Line) + for i.Next() { + ls := labelsCache(i.Labels()) + Outputs[*outputMode].Print(i.Entry().Timestamp, &ls, i.Entry().Line) } if err := i.Error(); err != nil { log.Fatalf("Error from iterator: %v", err) } } - -func printLogEntry(ts time.Time, lbls string, line string) { - fmt.Println( - color.BlueString(ts.Format(time.RFC3339)), - color.RedString(lbls), - strings.TrimSpace(line), - ) -} - -func padLabel(ls labels.Labels, maxLabelsLen int) string { - labels := ls.String() - if len(labels) < maxLabelsLen { - labels += strings.Repeat(" ", maxLabelsLen-len(labels)) - } - return labels -} - -func mustParseLabels(labels string) labels.Labels { - ls, err := parser.Labels(labels) - if err != nil { - log.Fatalf("Failed to parse labels: %+v", err) - } - return ls -} - -func parseLabels(resp *logproto.QueryResponse) (map[string]labels.Labels, []labels.Labels) { - cache := make(map[string]labels.Labels, len(resp.Streams)) - lss := make([]labels.Labels, 0, len(resp.Streams)) - for _, stream := range resp.Streams { - ls := mustParseLabels(stream.Labels) - cache[stream.Labels] = ls - lss = append(lss, ls) - } - return cache, lss -} - -func commonLabels(lss []labels.Labels) labels.Labels { - if len(lss) == 0 { - return nil - } - - result := lss[0] - for i := 1; i < len(lss); i++ { - result = intersect(result, lss[i]) - } - return result -} - -func intersect(a, b labels.Labels) labels.Labels { - var result labels.Labels - for i, j := 0, 0; i < len(a) && j < len(b); { - k := strings.Compare(a[i].Name, b[j].Name) - switch { - case k == 0: - if a[i].Value == b[j].Value { - result = append(result, a[i]) - } - i++ - j++ - case k < 0: - i++ - case k > 0: - j++ - } - } - return result -} - -// subtract b from a -func subtract(a, b labels.Labels) labels.Labels { - var result labels.Labels - i, j := 0, 0 - for i < len(a) && j < len(b) { - k := strings.Compare(a[i].Name, b[j].Name) - if k != 0 || a[i].Value != b[j].Value { - result = append(result, a[i]) - } - switch { - case k == 0: - i++ - j++ - case k < 0: - i++ - case k > 0: - j++ - } - } - for ; i < len(a); i++ { - result = append(result, a[i]) - } - return result -} diff --git a/cmd/logcli/query_test.go b/cmd/logcli/query_test.go new file mode 100644 index 0000000000000..a8a3db231df97 --- /dev/null +++ b/cmd/logcli/query_test.go @@ -0,0 +1,130 @@ +package main + +import ( + "reflect" + "testing" + + "github.com/prometheus/prometheus/pkg/labels" +) + +func Test_commonLabels(t *testing.T) { + type args struct { + lss []labels.Labels + } + tests := []struct { + name string + args args + want labels.Labels + }{ + { + "Extract common labels source > target", + args{ + []labels.Labels{mustParseLabels(`{foo="bar", bar="foo"}`), mustParseLabels(`{bar="foo", foo="foo", baz="baz"}`)}, + }, + mustParseLabels(`{bar="foo"}`), + }, + { + "Extract common labels source > target", + args{ + []labels.Labels{mustParseLabels(`{foo="bar", bar="foo"}`), mustParseLabels(`{bar="foo", foo="bar", baz="baz"}`)}, + }, + mustParseLabels(`{foo="bar", bar="foo"}`), + }, + { + "Extract common labels source < target", + args{ + []labels.Labels{mustParseLabels(`{foo="bar", bar="foo"}`), mustParseLabels(`{bar="foo"}`)}, + }, + mustParseLabels(`{bar="foo"}`), + }, + { + "Extract common labels source < target no common", + args{ + []labels.Labels{mustParseLabels(`{foo="bar", bar="foo"}`), mustParseLabels(`{fo="bar"}`)}, + }, + labels.Labels{}, + }, + { + "Extract common labels source = target no common", + args{ + []labels.Labels{mustParseLabels(`{foo="bar"}`), mustParseLabels(`{fooo="bar"}`)}, + }, + labels.Labels{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := commonLabels(tt.args.lss); !reflect.DeepEqual(got, tt.want) { + t.Errorf("commonLabels() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_subtract(t *testing.T) { + type args struct { + a labels.Labels + b labels.Labels + } + tests := []struct { + name string + args args + want labels.Labels + }{ + { + "Subtract labels source > target", + args{ + mustParseLabels(`{foo="bar", bar="foo"}`), + mustParseLabels(`{bar="foo", foo="foo", baz="baz"}`), + }, + mustParseLabels(`{foo="bar"}`), + }, + { + "Subtract labels source < target", + args{ + mustParseLabels(`{foo="bar", bar="foo"}`), + mustParseLabels(`{bar="foo"}`), + }, + mustParseLabels(`{foo="bar"}`), + }, + { + "Subtract labels source < target no sub", + args{ + mustParseLabels(`{foo="bar", bar="foo"}`), + mustParseLabels(`{fo="bar"}`), + }, + mustParseLabels(`{bar="foo", foo="bar"}`), + }, + { + "Subtract labels source = target no sub", + args{ + mustParseLabels(`{foo="bar"}`), + mustParseLabels(`{fiz="buz"}`), + }, + mustParseLabels(`{foo="bar"}`), + }, + { + "Subtract labels source > target no sub", + args{ + mustParseLabels(`{foo="bar"}`), + mustParseLabels(`{fiz="buz", foo="baz"}`), + }, + mustParseLabels(`{foo="bar"}`), + }, + { + "Subtract labels source > target no sub", + args{ + mustParseLabels(`{a="b", foo="bar", baz="baz", fizz="fizz"}`), + mustParseLabels(`{foo="bar", baz="baz", buzz="buzz", fizz="fizz"}`), + }, + mustParseLabels(`{a="b"}`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := subtract(tt.args.a, tt.args.b); !reflect.DeepEqual(got, tt.want) { + t.Errorf("subtract() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/logcli/tail.go b/cmd/logcli/tail.go index 51e64bd221e0e..94ee75b3432ec 100644 --- a/cmd/logcli/tail.go +++ b/cmd/logcli/tail.go @@ -2,8 +2,11 @@ package main import ( "log" + "strings" - "github.com/grafana/loki/pkg/logproto" + "github.com/grafana/loki/pkg/querier" + + "github.com/fatih/color" ) func tailQuery() { @@ -12,21 +15,58 @@ func tailQuery() { log.Fatalf("Tailing logs failed: %+v", err) } - stream := new(logproto.Stream) + tailReponse := new(querier.TailResponse) + + if len(*ignoreLabelsKey) > 0 { + log.Println("Ingoring labels key:", color.RedString(strings.Join(*ignoreLabelsKey, ","))) + } + + if len(*showLabelsKey) > 0 { + log.Println("Print only labels key:", color.RedString(strings.Join(*showLabelsKey, ","))) + } for { - err := conn.ReadJSON(stream) + err := conn.ReadJSON(tailReponse) if err != nil { log.Println("Error reading stream:", err) return } labels := "" - if !*noLabels { - labels = stream.Labels + for _, stream := range tailReponse.Streams { + if !*noLabels { + + if len(*ignoreLabelsKey) > 0 || len(*showLabelsKey) > 0 { + + ls := mustParseLabels(stream.GetLabels()) + + if len(*showLabelsKey) > 0 { + ls = ls.MatchLabels(true, *showLabelsKey...) + } + + if len(*ignoreLabelsKey) > 0 { + ls = ls.MatchLabels(false, *ignoreLabelsKey...) + } + + labels = ls.String() + + } else { + + labels = stream.Labels + } + } + + for _, entry := range stream.Entries { + lbls := mustParseLabels(labels) + Outputs[*outputMode].Print(entry.Timestamp, &lbls, entry.Line) + } + } - for _, entry := range stream.Entries { - printLogEntry(entry.Timestamp, labels, entry.Line) + if len(tailReponse.DroppedEntries) != 0 { + log.Println("Server dropped following entries due to slow client") + for _, d := range tailReponse.DroppedEntries { + log.Println(d.Timestamp, d.Labels) + } } } } diff --git a/cmd/logcli/utils.go b/cmd/logcli/utils.go new file mode 100644 index 0000000000000..6054f86ff6e70 --- /dev/null +++ b/cmd/logcli/utils.go @@ -0,0 +1,97 @@ +package main + +import ( + "log" + "sort" + "strings" + + "github.com/grafana/loki/pkg/logproto" + "github.com/prometheus/prometheus/pkg/labels" + "github.com/prometheus/prometheus/promql" +) + +// add some padding after labels +func padLabel(ls labels.Labels, maxLabelsLen int) string { + labels := ls.String() + if len(labels) < maxLabelsLen { + labels += strings.Repeat(" ", maxLabelsLen-len(labels)) + } + return labels +} + +// parse labels from string +func mustParseLabels(labels string) labels.Labels { + ls, err := promql.ParseMetric(labels) + if err != nil { + log.Fatalf("Failed to parse labels: %+v", err) + } + return ls +} + +// parse labels from response stream +func parseLabels(resp *logproto.QueryResponse) (map[string]labels.Labels, []labels.Labels) { + cache := make(map[string]labels.Labels, len(resp.Streams)) + lss := make([]labels.Labels, 0, len(resp.Streams)) + for _, stream := range resp.Streams { + ls := mustParseLabels(stream.Labels) + cache[stream.Labels] = ls + lss = append(lss, ls) + } + return cache, lss +} + +// return commonLabels labels between given lavels set +func commonLabels(lss []labels.Labels) labels.Labels { + if len(lss) == 0 { + return nil + } + + result := lss[0] + for i := 1; i < len(lss); i++ { + result = intersect(result, lss[i]) + } + return result +} + +// intersect two labels set +func intersect(a, b labels.Labels) labels.Labels { + + set := labels.Labels{} + ma := a.Map() + mb := b.Map() + + for ka, va := range ma { + if vb, ok := mb[ka]; ok { + if vb == va { + set = append(set, labels.Label{ + Name: ka, + Value: va, + }) + } + } + } + sort.Sort(set) + return set +} + +// subtract labels set b from labels set a +func subtract(a, b labels.Labels) labels.Labels { + + set := labels.Labels{} + ma := a.Map() + mb := b.Map() + + for ka, va := range ma { + if vb, ok := mb[ka]; ok { + if vb == va { + continue + } + } + set = append(set, labels.Label{ + Name: ka, + Value: va, + }) + } + sort.Sort(set) + return set +} diff --git a/cmd/loki-canary/Dockerfile b/cmd/loki-canary/Dockerfile new file mode 100644 index 0000000000000..fbfb024a78061 --- /dev/null +++ b/cmd/loki-canary/Dockerfile @@ -0,0 +1,14 @@ +# Directories in this file are referenced from the root of the project not this folder +# This file is intented to be called from the root like so: +# docker build -t grafana/promtail -f cmd/promtail/Dockerfile . + +FROM grafana/loki-build-image:0.2.1 as build +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN make clean && make loki-canary + +FROM alpine:3.9 +RUN apk add --update --no-cache ca-certificates +COPY --from=build /go/src/github.com/grafana/loki/cmd/loki-canary/loki-canary /usr/bin/loki-canary +ENTRYPOINT [ "/usr/bin/loki-canary" ] diff --git a/cmd/loki-canary/main.go b/cmd/loki-canary/main.go new file mode 100644 index 0000000000000..a289a1631165e --- /dev/null +++ b/cmd/loki-canary/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + "os" + "os/signal" + "strconv" + "syscall" + "time" + + "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/grafana/loki/pkg/canary/comparator" + "github.com/grafana/loki/pkg/canary/reader" + "github.com/grafana/loki/pkg/canary/writer" +) + +func main() { + + lName := flag.String("labelname", "name", "The label name for this instance of loki-canary to use in the log selector") + lVal := flag.String("labelvalue", "loki-canary", "The unique label value for this instance of loki-canary to use in the log selector") + port := flag.Int("port", 3500, "Port which loki-canary should expose metrics") + addr := flag.String("addr", "", "The Loki server URL:Port, e.g. loki:3100") + tls := flag.Bool("tls", false, "Does the loki connection use TLS?") + user := flag.String("user", "", "Loki username") + pass := flag.String("pass", "", "Loki password") + + interval := flag.Duration("interval", 1000*time.Millisecond, "Duration between log entries") + size := flag.Int("size", 100, "Size in bytes of each log line") + wait := flag.Duration("wait", 60*time.Second, "Duration to wait for log entries before reporting them lost") + pruneInterval := flag.Duration("pruneinterval", 60*time.Second, "Frequency to check sent vs received logs, also the frequency which queries for missing logs will be dispatched to loki") + buckets := flag.Int("buckets", 10, "Number of buckets in the response_latency histogram") + flag.Parse() + + if *addr == "" { + _, _ = fmt.Fprintf(os.Stderr, "Must specify a Loki address with -addr\n") + os.Exit(1) + } + + sentChan := make(chan time.Time) + receivedChan := make(chan time.Time) + + w := writer.NewWriter(os.Stdout, sentChan, *interval, *size) + r := reader.NewReader(os.Stderr, receivedChan, *tls, *addr, *user, *pass, *lName, *lVal) + c := comparator.NewComparator(os.Stderr, *wait, *pruneInterval, *buckets, sentChan, receivedChan, r) + + http.Handle("/metrics", promhttp.Handler()) + go func() { + err := http.ListenAndServe(":"+strconv.Itoa(*port), nil) + if err != nil { + panic(err) + } + }() + + interrupt := make(chan os.Signal, 1) + terminate := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + signal.Notify(terminate, syscall.SIGTERM) + + for { + select { + case <-interrupt: + _, _ = fmt.Fprintf(os.Stderr, "suspending indefinetely\n") + w.Stop() + r.Stop() + c.Stop() + case <-terminate: + _, _ = fmt.Fprintf(os.Stderr, "shutting down\n") + w.Stop() + r.Stop() + c.Stop() + return + } + } + +} diff --git a/cmd/loki/Dockerfile b/cmd/loki/Dockerfile index feb074da4a561..81111e192f0d4 100644 --- a/cmd/loki/Dockerfile +++ b/cmd/loki/Dockerfile @@ -1,6 +1,17 @@ +# Directories in this file are referenced from the root of the project not this folder +# This file is intented to be called from the root like so: +# docker build -t grafana/loki -f cmd/loki/Dockerfile . + +FROM grafana/loki-build-image:0.2.1 as build +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN make clean && make loki + FROM alpine:3.9 RUN apk add --update --no-cache ca-certificates -COPY loki /bin/loki -COPY loki-local-config.yaml /etc/loki/local-config.yaml +COPY --from=build /go/src/github.com/grafana/loki/cmd/loki/loki /usr/bin/loki +COPY cmd/loki/loki-local-config.yaml /etc/loki/local-config.yaml EXPOSE 80 -ENTRYPOINT [ "/bin/loki" ] +ENTRYPOINT [ "/usr/bin/loki" ] +CMD ["-config.file=/etc/loki/local-config.yaml"] diff --git a/cmd/loki/Dockerfile.debug b/cmd/loki/Dockerfile.debug new file mode 100644 index 0000000000000..58ff97d27b898 --- /dev/null +++ b/cmd/loki/Dockerfile.debug @@ -0,0 +1,28 @@ +# Directories in this file are referenced from the root of the project not this folder +# This file is intented to be called from the root like so: +# docker build -t grafana/loki -f cmd/loki/Dockerfile.debug . + +FROM grafana/loki-build-image as build +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN make clean && make loki-debug + +FROM alpine:3.9 +RUN apk add --update --no-cache ca-certificates +COPY --from=build /go/src/github.com/grafana/loki/cmd/loki/loki-debug /usr/bin/loki-debug +COPY --from=build /go/bin/dlv /usr/bin/dlv +COPY cmd/loki/loki-local-config.yaml /etc/loki/local-config.yaml +EXPOSE 80 + +# Expose 40000 for delve +EXPOSE 40000 + +# Allow delve to run on Alpine based containers. +RUN apk add --no-cache libc6-compat + +# Run delve, ending with -- because we pass params via kubernetes, per the docs: +# Pass flags to the program you are debugging using --, for example:` +# dlv exec ./hello -- server --config conf/config.toml` +ENTRYPOINT ["/usr/bin/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "exec", "/usr/bin/loki-debug", "--"] +CMD ["-config.file=/etc/loki/local-config.yaml"] diff --git a/cmd/loki/loki-local-config.yaml b/cmd/loki/loki-local-config.yaml index 24d7a8344a528..3320a99ebdde2 100644 --- a/cmd/loki/loki-local-config.yaml +++ b/cmd/loki/loki-local-config.yaml @@ -7,13 +7,16 @@ ingester: lifecycler: address: 127.0.0.1 ring: - store: inmemory + kvstore: + store: inmemory replication_factor: 1 - chunk_idle_period: 15m + final_sleep: 0s + chunk_idle_period: 5m + chunk_retain_period: 30s schema_config: configs: - - from: 0 + - from: 2018-04-15 store: boltdb object_store: filesystem schema: v9 @@ -30,3 +33,23 @@ storage_config: limits_config: enforce_metric_name: false + reject_old_samples: true + reject_old_samples_max_age: 168h + +chunk_store_config: + max_look_back_period: 0 + +table_manager: + chunk_tables_provisioning: + inactive_read_throughput: 0 + inactive_write_throughput: 0 + provisioned_read_throughput: 0 + provisioned_write_throughput: 0 + index_tables_provisioning: + inactive_read_throughput: 0 + inactive_write_throughput: 0 + provisioned_read_throughput: 0 + provisioned_write_throughput: 0 + retention_deletes_enabled: false + retention_period: 0 + diff --git a/cmd/loki/main.go b/cmd/loki/main.go index 073e8a0bd88ed..60676cf3603ac 100644 --- a/cmd/loki/main.go +++ b/cmd/loki/main.go @@ -4,16 +4,19 @@ import ( "flag" "fmt" "os" + "reflect" "github.com/go-kit/kit/log/level" "github.com/grafana/loki/pkg/helpers" "github.com/grafana/loki/pkg/loki" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/version" + "github.com/weaveworks/common/logging" "github.com/weaveworks/common/tracing" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/flagext" + "github.com/cortexproject/cortex/pkg/util/validation" ) func init() { @@ -29,6 +32,15 @@ func main() { flagext.RegisterFlags(&cfg) flag.Parse() + // LimitsConfig has a customer UnmarshalYAML that will set the defaults to a global. + // This global is set to the config passed into the last call to `NewOverrides`. If we don't + // call it atleast once, the defaults are set to an empty struct. + // We call it with the flag values so that the config file unmarshalling only overrides the values set in the config. + if _, err := validation.NewOverrides(cfg.LimitsConfig); err != nil { + level.Error(util.Logger).Log("msg", "error loading limits", "err", err) + os.Exit(1) + } + util.InitLogger(&cfg.Server) if configFile != "" { @@ -38,6 +50,13 @@ func main() { } } + // Re-init the logger which will now honor a different log level set in cfg.Server + if reflect.DeepEqual(&cfg.Server.LogLevel, &logging.Level{}) { + level.Error(util.Logger).Log("msg", "invalid log level") + os.Exit(1) + } + util.InitLogger(&cfg.Server) + // Setting the environment variable JAEGER_AGENT_HOST enables tracing trace := tracing.NewFromEnv(fmt.Sprintf("loki-%s", cfg.Target)) defer func() { diff --git a/cmd/promtail/Dockerfile b/cmd/promtail/Dockerfile index 136672534b742..58ba144f46210 100644 --- a/cmd/promtail/Dockerfile +++ b/cmd/promtail/Dockerfile @@ -1,6 +1,16 @@ +# Directories in this file are referenced from the root of the project not this folder +# This file is intented to be called from the root like so: +# docker build -t grafana/promtail -f cmd/promtail/Dockerfile . + +FROM grafana/loki-build-image:0.2.1 as build +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN make clean && make promtail + FROM alpine:3.9 -RUN apk add --update --no-cache ca-certificates -ADD promtail /usr/bin -COPY promtail-local-config.yaml /etc/promtail/local-config.yaml -COPY promtail-docker-config.yaml /etc/promtail/docker-config.yaml +RUN apk add --update --no-cache ca-certificates tzdata +COPY --from=build /go/src/github.com/grafana/loki/cmd/promtail/promtail /usr/bin/promtail +COPY cmd/promtail/promtail-local-config.yaml /etc/promtail/local-config.yaml +COPY cmd/promtail/promtail-docker-config.yaml /etc/promtail/docker-config.yaml ENTRYPOINT ["/usr/bin/promtail"] diff --git a/cmd/promtail/Dockerfile.debug b/cmd/promtail/Dockerfile.debug new file mode 100644 index 0000000000000..fc4d3fe35d778 --- /dev/null +++ b/cmd/promtail/Dockerfile.debug @@ -0,0 +1,28 @@ +# Directories in this file are referenced from the root of the project not this folder +# This file is intented to be called from the root like so: +# docker build -t grafana/promtail -f cmd/promtail/Dockerfile.debug . + +FROM grafana/loki-build-image as build +ARG GOARCH="amd64" +COPY . /go/src/github.com/grafana/loki +WORKDIR /go/src/github.com/grafana/loki +RUN make clean && make promtail-debug + + +FROM alpine:3.9 +RUN apk add --update --no-cache ca-certificates tzdata +COPY --from=build /go/src/github.com/grafana/loki/cmd/promtail/promtail-debug /usr/bin/promtail-debug +COPY --from=build /go/bin/dlv /usr/bin/dlv +COPY cmd/promtail/promtail-local-config.yaml /etc/promtail/local-config.yaml +COPY cmd/promtail/promtail-docker-config.yaml /etc/promtail/docker-config.yaml + +# Expose 40000 for delve +EXPOSE 40000 + +# Allow delve to run on Alpine based containers. +RUN apk add --no-cache libc6-compat + +# Run delve, ending with -- because we pass params via kubernetes, per the docs: +# Pass flags to the program you are debugging using --, for example:` +# dlv exec ./hello -- server --config conf/config.toml` +ENTRYPOINT ["/usr/bin/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "exec", "/usr/bin/promtail-debug", "--"] diff --git a/cmd/promtail/main.go b/cmd/promtail/main.go index 77ece24615fef..fac17045e319d 100644 --- a/cmd/promtail/main.go +++ b/cmd/promtail/main.go @@ -3,12 +3,14 @@ package main import ( "flag" "os" + "reflect" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/flagext" "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/version" + "github.com/weaveworks/common/logging" "github.com/grafana/loki/pkg/helpers" "github.com/grafana/loki/pkg/promtail" @@ -28,7 +30,7 @@ func main() { flagext.RegisterFlags(&config) flag.Parse() - util.InitLogger(&config.ServerConfig) + util.InitLogger(&config.ServerConfig.Config) if configFile != "" { if err := helpers.LoadConfig(configFile, &config); err != nil { @@ -37,6 +39,13 @@ func main() { } } + // Re-init the logger which will now honor a different log level set in ServerConfig.Config + if reflect.DeepEqual(&config.ServerConfig.Config.LogLevel, &logging.Level{}) { + level.Error(util.Logger).Log("msg", "invalid log level") + os.Exit(1) + } + util.InitLogger(&config.ServerConfig.Config) + p, err := promtail.New(config) if err != nil { level.Error(util.Logger).Log("msg", "error creating promtail", "error", err) diff --git a/cmd/promtail/promtail-docker-config.yaml b/cmd/promtail/promtail-docker-config.yaml index 8dc8f27307c72..9dca263256802 100644 --- a/cmd/promtail/promtail-docker-config.yaml +++ b/cmd/promtail/promtail-docker-config.yaml @@ -5,12 +5,11 @@ server: positions: filename: /tmp/positions.yaml -client: - url: http://loki:3100/api/prom/push +clients: + - url: http://loki:3100/api/prom/push scrape_configs: - job_name: system - entry_parser: raw static_configs: - targets: - localhost diff --git a/cmd/promtail/promtail-local-config.yaml b/cmd/promtail/promtail-local-config.yaml index d5b13c5e0c23a..9744741c57381 100644 --- a/cmd/promtail/promtail-local-config.yaml +++ b/cmd/promtail/promtail-local-config.yaml @@ -5,12 +5,11 @@ server: positions: filename: /tmp/positions.yaml -client: - url: http://localhost:3100/api/prom/push +clients: + - url: http://localhost:3100/api/prom/push scrape_configs: - job_name: system - entry_parser: raw static_configs: - targets: - localhost diff --git a/debug/README.md b/debug/README.md new file mode 100644 index 0000000000000..b4e571325a2ab --- /dev/null +++ b/debug/README.md @@ -0,0 +1,57 @@ +## Debug images + +To build debug images run + +```shell +make debug +``` + +You can use the `docker-compose.yaml` in this directory to launch the debug versions of the image in docker + + +## Promtail in kubernetes + +If you want to debug promtail in kubernetes, I have done so with the ksonnet setup: + +```shell +ks init promtail +cd promtail +ks env add promtail +jb init +jb install github.com/grafana/loki/production/ksonnet/promtail +vi environments/promtail/main.jsonnet +``` + +Replace the contents with: + +```jsonnet +local promtail = import 'promtail/promtail.libsonnet'; + + +promtail + { + _images+:: { + promtail: 'grafana/promtail-debug:latest', + }, + _config+:: { + namespace: 'default', + + promtail_config+: { + external_labels+: { + cluster: 'some_cluster_name', + }, + scheme: 'https', + hostname: 'hostname', + username: 'username', + password: 'password', + }, + }, +} +``` + +change the `some_cluster_name` to anything meaningful to help find your logs in loki + +also update the `hostname`, `username`, and `password` for your loki instance. + +## Loki in kubernetes + +Haven't tried this yet, it works from docker-compose so it should run in kubernetes just fine also. \ No newline at end of file diff --git a/debug/docker-compose.yaml b/debug/docker-compose.yaml new file mode 100644 index 0000000000000..88c0811ac1256 --- /dev/null +++ b/debug/docker-compose.yaml @@ -0,0 +1,37 @@ +version: "3" + +networks: + loki: + +services: + loki: + # this is required according to https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code#linuxdocker + security_opt: + - seccomp:unconfined + image: grafana/loki-debug:latest + ports: + - "40000:40000" + - "3100:3100" + command: -config.file=/etc/loki/local-config.yaml + networks: + - loki + + promtail: + # this is required according to https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code#linuxdocker + security_opt: + - seccomp:unconfined + image: grafana/promtail-debug:latest + ports: + - "40100:40000" + volumes: + - /var/log:/var/log + command: -config.file=/etc/promtail/docker-config.yaml + networks: + - loki + + grafana: + image: grafana/grafana:master + ports: + - "3000:3000" + networks: + - loki diff --git a/docs/api.md b/docs/api.md index 9980878ffec59..2432f307dfe09 100644 --- a/docs/api.md +++ b/docs/api.md @@ -26,12 +26,12 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o For doing queries, accepts the following parameters in the query-string: - - `query`: a logQL query + - `query`: a [logQL query](./usage.md) (eg: `{name=~"mysql.+"}` or `{name=~"mysql.+"} |= "error"`) - `limit`: max number of entries to return - - `start`: the start time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is always one hour ago. - - `end`: the end time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is current time. + - `start`: the start time for the query, as a nanosecond Unix epoch (nanoseconds since 1970) or as RFC3339Nano (eg: "2006-01-02T15:04:05.999999999-07:00"). Default is always one hour ago. + - `end`: the end time for the query, as a nanosecond Unix epoch (nanoseconds since 1970) or as RFC3339Nano (eg: "2006-01-02T15:04:05.999999999-07:00"). Default is current time. - `direction`: `forward` or `backward`, useful when specifying a limit. Default is backward. - - `regexp`: a regex to filter the returned results, will eventually be rolled into the query language + - `regexp`: a regex to filter the returned results Loki needs to query the index store in order to find log streams for particular labels and the store is spread out by time, so you need to specify the start and end labels accordingly. Querying a long time into the history will cause additional @@ -39,14 +39,14 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o Responses looks like this: - ``` + ```json { "streams": [ { "labels": "{instance=\"...\", job=\"...\", namespace=\"...\"}", "entries": [ { - "timestamp": "2018-06-27T05:20:28.699492635Z", + "ts": "2018-06-27T05:20:28.699492635Z", "line": "..." }, ... @@ -59,11 +59,14 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o - `GET /api/prom/label` - For retrieving the names of the labels one can query on. + For doing label name queries, accepts the following parameters in the query-string: + + - `start`: the start time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is always 6 hour ago. + - `end`: the end time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is current time. Responses looks like this: - ``` + ```json { "values": [ "instance", @@ -74,11 +77,15 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o ``` - `GET /api/prom/label//values` - For retrieving the label values one can query on. + + For doing label values queries, accepts the following parameters in the query-string: + + - `start`: the start time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is always 6 hour ago. + - `end`: the end time for the query, as a nanosecond Unix epoch (nanoseconds since 1970). Default is current time. Responses looks like this: - ``` + ```json { "values": [ "default", @@ -88,6 +95,20 @@ The Loki server has the following API endpoints (_Note:_ Authentication is out o } ``` -## Example of using the API in a third-party client library +- `GET /ready` + + This endpoint returns 200 when Loki ingester is ready to accept traffic. If you're running Loki on Kubernetes, this endpoint can be used as readiness probe. + +- `GET /flush` + + This endpoint triggers a flush of all in memory chunks in the ingester. Mainly used for local testing. + +- `GET /metrics` + + This endpoint returns Loki metrics for Prometheus. See "[Operations > Observability > Metrics](./operations.md)" to have a list of exported metrics. + + +## Examples of using the API in a third-party client library -Take a look at this [client](https://github.com/afiskon/promtail-client), but be aware that the API is not stable yet. +1) Take a look at this [client](https://github.com/afiskon/promtail-client), but be aware that the API is not stable yet (Golang). +2) Example on [Python3](https://github.com/sleleko/devops-kb/blob/master/python/push-to-loki.py) diff --git a/docs/canary/README.md b/docs/canary/README.md new file mode 100644 index 0000000000000..45144399b6c8c --- /dev/null +++ b/docs/canary/README.md @@ -0,0 +1,108 @@ + +# loki-canary + +A standalone app to audit the log capturing performance of Loki. + +## how it works + +![block_diagram](block.png) + +loki-canary writes a log to a file and stores the timestamp in an internal array, the contents look something like this: + +```nohighlight +1557935669096040040 ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp +``` + +The relevant part is the timestamp, the `p`'s are just filler bytes to make the size of the log configurable. + +Promtail (or another agent) then reads the log file and ships it to Loki. + +Meanwhile loki-canary opens a websocket connection to loki and listens for logs it creates + +When a log is received on the websocket, the timestamp in the log message is compared to the internal array. + +If the received log is: + + * The next in the array to be received, it is removed from the array and the (current time - log timestamp) is recorded in the `response_latency` histogram, this is the expected behavior for well behaving logs + * Not the next in the array received, is is removed from the array, the response time is recorded in the `response_latency` histogram, and the `out_of_order_entries` counter is incremented + * Not in the array at all, it is checked against a separate list of received logs to either increment the `duplicate_entries` counter or the `unexpected_entries` counter. + +In the background, loki-canary also runs a timer which iterates through all the entries in the internal array, if any are older than the duration specified by the `-wait` flag (default 60s), they are removed from the array and the `websocket_missing_entries` counter is incremented. Then an additional query is made directly to loki for these missing entries to determine if they were actually missing or just didn't make it down the websocket. If they are not found in the followup query the `missing_entries` counter is incremented. + +## building and running + +`make` will run tests and build a docker image + +`make build` will create a binary `loki-canary` alongside the makefile + +To run the image, you can do something simple like: + +`kubectl run loki-canary --generator=run-pod/v1 --image=grafana/loki-canary:latest --restart=Never --image-pull-policy=Never --labels=name=loki-canary -- -addr=loki:3100` + +Or you can do something more complex like deploy it as a daemonset, there is a ksonnet setup for this in the `production` folder, you can import it using jsonnet-bundler: + +```shell +jb install github.com/grafana/loki-canary/production/ksonnet/loki-canary +``` + +Then in your ksonnet environments `main.jsonnet` you'll want something like this: + +```nohighlight +local loki_canary = import 'loki-canary/loki-canary.libsonnet'; + +loki_canary { + loki_canary_args+:: { + addr: "loki:3100", + port: 80, + labelname: "instance", + interval: "100ms", + size: 1024, + wait: "3m", + }, + _config+:: { + namespace: "default", + } +} + +``` + +## config + +It is required to pass in the Loki address with the `-addr` flag, if your server uses TLS, also pass `-tls=true` (this will create a wss:// instead of ws:// connection) + +You should also pass the `-labelname` and `-labelvalue` flags, these are used by loki-canary to filter the log stream to only process logs for this instance of loki-canary, so they must be unique per each of your loki-canary instances. The ksonnet config in this project accomplishes this by passing in the pod name as the labelvalue + +If you get a high number of `unexpected_entries` you may not be waiting long enough and should increase `-wait` from 60s to something larger. + +__Be cognizant__ of the relationship between `pruneinterval` and the `interval`. For example, with an interval of 10ms (100 logs per second) and a prune interval of 60s, you will write 6000 logs per minute, if those logs were not received over the websocket, the canary will attempt to query loki directly to see if they are completely lost. __However__ the query return is limited to 1000 results so you will not be able to return all the logs even if they did make it to Loki. + +__Likewise__, if you lower the `pruneinterval` you risk causing a denial of service attack as all your canaries attempt to query for missing logs at whatever your `pruneinterval` is defined at. + +All options: + +```nohighlight + -addr string + The Loki server URL:Port, e.g. loki:3100 + -buckets int + Number of buckets in the response_latency histogram (default 10) + -interval duration + Duration between log entries (default 1s) + -labelname string + The label name for this instance of loki-canary to use in the log selector (default "name") + -labelvalue string + The unique label value for this instance of loki-canary to use in the log selector (default "loki-canary") + -pass string + Loki password + -port int + Port which loki-canary should expose metrics (default 3500) + -pruneinterval duration + Frequency to check sent vs received logs, also the frequency which queries for missing logs will be dispatched to loki (default 1m0s) + -size int + Size in bytes of each log line (default 100) + -tls + Does the loki connection use TLS? + -user string + Loki username + -wait duration + Duration to wait for log entries before reporting them lost (default 1m0s) +``` diff --git a/docs/canary/block.png b/docs/canary/block.png new file mode 100644 index 0000000000000000000000000000000000000000..f7dd39047bed776a536674e841705e43c3cdea40 GIT binary patch literal 56500 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] [ ...] A command-line for loki. Flags: - --help Show context-sensitive help (also try --help-long and --help-man). - --addr="" Server address, need to specify. - --username="" Username for HTTP basic auth. - --password="" Password for HTTP basic auth. + --help Show context-sensitive help (also try --help-long and --help-man). + -q, --quiet suppress everything but log lines + -o, --output=default specify output mode [default, raw, jsonl] + --addr="https://logs-us-west1.grafana.net" + Server address. + --username="" Username for HTTP basic auth. + --password="" Password for HTTP basic auth. + --ca-cert="" Path to the server Certificate Authority. + --tls-skip-verify Server certificate TLS skip verify. + --cert="" Path to the client certificate. + --key="" Path to the client certificate key. Commands: help [...] @@ -72,7 +79,7 @@ Commands: query [] [] Run a LogQL query. - labels