Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22108a2782 | ||
|
|
742056bbef | ||
|
|
2556dd07b3 | ||
|
|
e43879b69c | ||
|
|
239bd874b2 | ||
|
|
c9b8b3f95a | ||
|
|
3454e907d3 | ||
|
|
d33376e03b | ||
|
|
f045f8bc95 | ||
|
|
3e5f174f6e | ||
|
|
34a21463b5 | ||
|
|
02fc893d4b | ||
|
|
7c342e17a1 | ||
|
|
8e23f61220 | ||
|
|
4a65020cbf | ||
|
|
f59aa6bfaa | ||
|
|
ef78f94cb5 | ||
|
|
1ed4dde60e | ||
|
|
959966d3eb | ||
|
|
07ffc18770 | ||
|
|
9773d39655 | ||
|
|
b41f755c08 | ||
|
|
226c5bce54 | ||
|
|
13dd12d737 | ||
|
|
078ffec475 | ||
|
|
0595fdd0ce |
12
.babelrc
12
.babelrc
@@ -1,10 +1,16 @@
|
||||
{
|
||||
"presets": ["env"],
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": false
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"transform-runtime",
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
"polyfill": false,
|
||||
"regenerator": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -30,25 +30,6 @@ changelog:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
|
||||
nfpm:
|
||||
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
replacements:
|
||||
amd64: 64-bit
|
||||
386: 32-bit
|
||||
arm64: ARM_64-bit
|
||||
arm: ARM_32-bit
|
||||
linux: Linux
|
||||
darwin: macOS
|
||||
|
||||
vendor: Amir Raminfar
|
||||
homepage: https://github.com/amir20/dozzle/
|
||||
maintainer: Amir Raminfar <findamir@gmail.com>
|
||||
license: MIT
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
|
||||
dockers:
|
||||
- image_templates:
|
||||
- "amir20/dozzle:{{ .Tag }}"
|
||||
|
||||
26
.travis.yml
Normal file
26
.travis.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.11"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install:
|
||||
- nvm install --lts
|
||||
- npm i -g npm
|
||||
- npm ci
|
||||
- go get -u github.com/gobuffalo/packr/packr
|
||||
|
||||
after_success:
|
||||
# docker login is required if you want to push docker images.
|
||||
# DOCKER_PASSWORD should be a secret in your .travis.yml configuration.
|
||||
# - test -n "$TRAVIS_TAG" && docker login -u=myuser -p="$DOCKER_PASSWORD"
|
||||
|
||||
deploy:
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: curl -sL https://git.io/goreleaser | bash
|
||||
on:
|
||||
tags: true
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
47
README.md
Normal file
47
README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# dozzle
|
||||
|
||||
Dozzle is a log viewer for Docker. It's free. It's small. And it's right in your browser. Oh, did I mention it is also real-time?
|
||||
|
||||
While dozzle should work for most, it is not meant to be a full logging solution. For enterprise use, I recommend you look at [Loggly](https://www.loggly.com), [Papertrail](https://papertrailapp.com) or [Kibana](https://www.elastic.co/products/kibana).
|
||||
|
||||
But if you don't want to pay for those service, then you are in luck! Dozzle will be able capture all logs from your containers and send them in real-time to your browser. Installation is also very easy.
|
||||
|
||||

|
||||
|
||||
## Getting dozzle
|
||||
|
||||
Dozzle is a very small Docker container (13.3MB virtual). Pull the latest release from the index:
|
||||
|
||||
$ docker pull amir20/dozzle:latest
|
||||
|
||||
## Using dozzle
|
||||
|
||||
The simplest way to use dozzle is to run the docker container. Also, mount the Docker Unix socket with `-volume` to `/var/run/docker.sock`:
|
||||
|
||||
$ docker run --name dozzle -d --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:8080 amir20/dozzle:latest
|
||||
|
||||
dozzle will be available at [http://localhost:8888/](http://localhost:8888/). You can change `-p 8888:8080` to any port. For example, if you want to view dozzle over port 4040 then you would do `-p 4040:8080`.
|
||||
|
||||
#### Security
|
||||
|
||||
dozzle doesn't support authentication out of the box. You can control the device dozzle binds to by passing `-addr` parameter. For example,
|
||||
|
||||
$ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:1224 amir20/dozzle:latest -addr localhost:1224
|
||||
|
||||
will bind to `localhost` on port `1224`. You can then use use reverse proxy to control who can see the dozzle.
|
||||
|
||||
#### Environment variable, DOCKER_API_VERSION
|
||||
|
||||
If you see
|
||||
|
||||
2018/10/31 08:53:17 Error response from daemon: client version 1.40 is too new. Maximum supported API version is 1.38
|
||||
|
||||
Then you need to modify `DOCKER_API_VERSION` to let dozzle know which version of the API is supported. By default, `DOCKER_API_VERSION=1.38` and you can change it to by passing `-e` flag. For example, this would change the `DOCKER_API_VERSION` to `1.20`
|
||||
|
||||
$ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -e DOCKER_API_VERSION=1.20 -p 8888:8080 amir20/dozzle:latest
|
||||
|
||||
If you are not sure what to set `DOCKER_API_VERSION` then run `docker version` which will show supported API version.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
@@ -1,10 +1,5 @@
|
||||
<template lang="html">
|
||||
<div class="content">
|
||||
<p>
|
||||
<router-link to="/">Go back</router-link>
|
||||
</p>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -14,4 +9,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
</style>
|
||||
.section.is-fullwidth {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css" integrity="sha256-dMQYvN6BU9M4mHK94P22cZ4dPGTSGOVP41yVXvXatws=" crossorigin="anonymous" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dozzle</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
|
||||
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="/main.js"></script>
|
||||
<section class="section is-fullwidth">
|
||||
<div id="app"></div>
|
||||
</section>
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,11 +1,11 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter from "vue-router";
|
||||
Vue.use(VueRouter);
|
||||
|
||||
import App from "./App.vue";
|
||||
import Index from "./pages/Index.vue";
|
||||
import Container from "./pages/Container.vue";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes = [
|
||||
{ path: "/", component: Index },
|
||||
{
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
<template lang="html">
|
||||
<pre ref="logs">
|
||||
|
||||
</pre>
|
||||
<ul ref="events" class="events"></ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { formatRelative } from "date-fns";
|
||||
let ws;
|
||||
|
||||
const parseMessage = data => {
|
||||
const date = new Date(data.substring(0, 30));
|
||||
const dateRelative = formatRelative(date, new Date());
|
||||
const message = data.substring(30);
|
||||
return {
|
||||
date,
|
||||
dateRelative,
|
||||
message
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
props: ["id"],
|
||||
name: "Container",
|
||||
@@ -15,14 +26,45 @@ export default {
|
||||
ws.onclose = e => console.log("Connection closed.");
|
||||
ws.onerror = e => console.error("Connection error: " + e.data);
|
||||
ws.onmessage = e => {
|
||||
const parent = this.$refs.logs;
|
||||
const item = document.createTextNode(e.data);
|
||||
const data = parseMessage(e.data);
|
||||
const parent = this.$refs.events;
|
||||
const item = document.createElement("li");
|
||||
item.className = "event";
|
||||
|
||||
const date = document.createElement("span");
|
||||
date.className = "date";
|
||||
date.innerHTML = data.dateRelative;
|
||||
item.appendChild(date);
|
||||
|
||||
const message = document.createElement("span");
|
||||
message.className = "text";
|
||||
message.innerHTML = data.message;
|
||||
item.appendChild(message);
|
||||
|
||||
parent.appendChild(item);
|
||||
parent.scrollIntoView({block: "end"});
|
||||
|
||||
this.$nextTick(() => item.scrollIntoView());
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.events {
|
||||
color: #ddd;
|
||||
background-color: #111;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
.event {
|
||||
font-family: monaco, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
padding: 0 15px 0 30px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.date {
|
||||
background-color: #262626;
|
||||
color: #258ccd;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="item in containers" class="columns unstyled box">
|
||||
<div class="column is-6">
|
||||
<router-link :to="{name: 'container', params: {id: item.Id}}">{{ item.Names[0] }}</router-link>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<code>{{ item.Image }}</code>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
{{ item.Status}}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<section class="section">
|
||||
<ul class="is-marginless is-paddless">
|
||||
<li v-for="item in containers" class=" unstyled box">
|
||||
<router-link :to="{name: 'container', params: {id: item.Id}}" class="columns">
|
||||
<div class="column is-6">
|
||||
<h2 class="is-2 hide-overflow">{{ item.Names[0] }}</h2>
|
||||
<span class="subtitle is-6 code hide-overflow">{{ item.Command}}</span>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<span class="code hide-overflow">{{ item.Image }}</span>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<span class="subtitle is-7">{{ item.Status}}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -31,4 +38,18 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
</style>
|
||||
.hide-overflow {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.code {
|
||||
background-color: #f5f5f5;
|
||||
color: #ff3860;
|
||||
font-size: 0.875em;
|
||||
font-weight: 400;
|
||||
padding: 0.25em 0.5em 0.25em;
|
||||
display: block;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
2
main.go
2
main.go
@@ -66,7 +66,7 @@ func logs(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "40"}
|
||||
options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "500", Timestamps: true}
|
||||
reader, err := cli.ContainerLogs(context.Background(), id, options)
|
||||
defer reader.Close()
|
||||
if err != nil {
|
||||
|
||||
1761
package-lock.json
generated
1761
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dozzle",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.10",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -24,17 +24,31 @@
|
||||
"vue-router": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/plugin-transform-runtime": "^7.1.0",
|
||||
"@vue/component-compiler-utils": "^2.3.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"parcel-bundler": "^1.10.3",
|
||||
"concurrently": "^4.0.1",
|
||||
"date-fns": "^2.0.0-alpha.25",
|
||||
"husky": "^1.1.2",
|
||||
"lint-staged": "^8.0.4",
|
||||
"parcel-bundler": "^1.10.3",
|
||||
"prettier": "^1.14.3",
|
||||
"vue-hot-reload-api": "^2.3.1",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue,css}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"browserslist": [
|
||||
">5%"
|
||||
">5%",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user