Skip to content

Commit

Permalink
improve log performance, add gzip, swap to code mirror, frontend impr…
Browse files Browse the repository at this point in the history
…ovements
  • Loading branch information
jpillora committed Oct 14, 2017
1 parent 40ad199 commit 1f826b6
Show file tree
Hide file tree
Showing 13 changed files with 669 additions and 403 deletions.
15 changes: 12 additions & 3 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package agent

import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
Expand All @@ -15,6 +16,7 @@ import (
"sync/atomic"
"time"

"github.com/NYTimes/gziphandler"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/jpillora/cookieauth"
"github.com/jpillora/ipfilter"
Expand All @@ -38,6 +40,7 @@ type agent struct {
data struct {
sync.Mutex
velox.State
Version string
Config Config
ChangedAt time.Time
Running bool
Expand All @@ -50,15 +53,17 @@ type agent struct {
}
}

func Run(c Config) error {
func Run(version string, c Config) error {
a := &agent{}
a.msgQueue = make(chan msg)
a.msgQueue = make(chan msg, 10000)
agentWriter := &msgQueuer{"agent", a.msgQueue}
a.log = log.New(io.MultiWriter(os.Stdout, agentWriter), "[webproc] ", log.LstdFlags)
a.procState = procChanging
a.procReqs = make(chan string)
a.procSigs = make(chan os.Signal)
//sync state
a.data.State.Throttle = 250 * time.Millisecond
a.data.Version = version
a.data.Config = c
a.data.Running = false
a.data.Manual = c.OnExit == OnExitIgnore
Expand All @@ -70,6 +75,10 @@ func Run(c Config) error {
//http
h := http.Handler(http.HandlerFunc(a.router))
//custom middleware stack
//4. gzip
gzipper, _ := gziphandler.NewGzipLevelAndMinSize(
gzip.DefaultCompression, 0)
h = gzipper(h)
//3. basic-auth middleware
if c.User != "" || c.Pass != "" {
h = cookieauth.Wrap(h, c.User, c.Pass)
Expand Down Expand Up @@ -103,8 +112,8 @@ func Run(c Config) error {
return fmt.Errorf("failed to start server: %s", err)
}
//threads
go a.readLog()
go a.runProc(c)
go a.readLog()
//load from disk
a.readFiles()
//catch all signals
Expand Down
2 changes: 1 addition & 1 deletion agent/agent_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (a *agent) serveSave(w http.ResponseWriter, r *http.Request) {
return
}
//ensure in file whitelist
for f, _ := range files {
for f := range files {
allowed := false
for _, configFile := range a.data.Config.ConfigurationFiles {
if f == configFile {
Expand Down
97 changes: 83 additions & 14 deletions agent/agent_static.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Config struct {
OnExit OnExit `help:"process exit action" default:"ignore"`
ConfigurationFiles []string `name:"config" type:"commalist" help:"comma-separated list of configuration files"`
RestartTimeout Duration `opts:"-"`
MaxLines int `help:"maximum number of log lines to show in webui" default:"1000"`
MaxLines int `help:"maximum number of log lines to show in webui" default:"5000"`
}

func LoadConfig(path string, c *Config) error {
Expand Down Expand Up @@ -71,7 +71,7 @@ func ValidateConfig(c *Config) error {
c.Port = 8080
}
if c.MaxLines == 0 {
c.MaxLines = 1000
c.MaxLines = 5000
}
switch c.Log {
case LogBoth, LogProxy, LogWebUI:
Expand All @@ -83,7 +83,7 @@ func ValidateConfig(c *Config) error {
default:
c.OnExit = OnExitIgnore
}
if c.RestartTimeout == 0 {
if c.RestartTimeout <= 0 {
c.RestartTimeout = Duration(30 * time.Second)
}
return nil
Expand Down
19 changes: 16 additions & 3 deletions agent/msg.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package agent

import "bytes"

type msg struct {
Pipe string `json:"p"`
Buff string `json:"b"`
Expand All @@ -10,10 +12,21 @@ type msgQueuer struct {
queue chan msg
}

func (lq *msgQueuer) Write(p []byte) (int, error) {
l := len(p)
func (lq *msgQueuer) Write(data []byte) (int, error) {
l := len(data)
if l > 0 {
lq.queue <- msg{lq.pipe, string(p)}
lines := bytes.Split(data, []byte("\n"))
lastIndex := len(lines) - 1
for i, d := range lines {
line := string(d)
if i != lastIndex {
line += "\n"
}
if line == "" {
continue
}
lq.queue <- msg{lq.pipe, line}
}
}
return l, nil
}
187 changes: 98 additions & 89 deletions agent/static/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ body {
body {
display: flex;
min-height: 100vh;
opacity: 0;
transition: opacity ease-in 0.6s;
}

body.loaded {
opacity: 1;
}

select {
Expand All @@ -25,48 +31,49 @@ select {
main {
display: flex;
flex-direction: row;
width: 100%;
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
}

.content {
/* flex item */
flex: 6;
/* flex container */
display: flex;
flex-wrap: nowrap;
flex-direction: column;
flex: 6;
width: 50%;
}
/*===================================*/

.controls {
flex: 1;
min-width: 110px;
/* flex item */
flex-grow: 0;
flex-shrink: 0;
flex-basis: 10em;
text-align: center;
padding: 10px;
border-right: 1px solid #aaa;
overflow-y: auto;
}

.controls .files {
margin-bottom: 20px;
}

.controls .checkmark.icon {
margin: 0;
}
.controls .inputs.icon {
display: none;
}
/*.controls span.connected {
font-size: 11px;
}
.controls span.disconnected {
font-size: 10px;
}*/
.controls .title.info.field {
text-decoration: underline;
}
.controls .info.field {
text-align: left;
}
.controls .status.field {
white-space: nowrap;
}
.controls .info.field .ui.checkbox {
width: 100%;
}
Expand All @@ -77,9 +84,14 @@ main {
font-size: 0.9em;
padding-left: 20px;
}

.follow.icon {
transition: opacity ease 0.3s;
.controls .version {
color: #ccc;
text-align: right;
margin: 25px 0 10px 0;
font-size: 0.8em;
}
.controls .version a {
color: #ccc;
}

.messages {
Expand All @@ -93,95 +105,92 @@ main {
}

/*===================================*/
.container {
position: relative;
flex: 1;

.CodeMirror {
height: 100%;
width: 100%;
}
.container.editor {
min-height: 200px;

.CodeMirror .cm-out {
color: #001dbf;
}
#editor {
font-family: monospace !important;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 100%;

.CodeMirror .cm-err {
color: #a50000;
}
.container.log {
width: 100%;
margin: 0;
padding: 10px;
min-height: 200px;
border-top: 1px solid #aaa;
overflow: auto;

.CodeMirror .cm-agent {
color: #666;
}
.container.log span {
display: none;

.CodeMirror .CodeMirror-vscrollbar,
.CodeMirror .CodeMirror-hscrollbar {
transition: opacity ease-in 0.3s;
opacity: 0;
}
.container.log.out span.out,
.container.log.err span.err,
.container.log.agent span.agent {
display: inline;

.CodeMirror:hover .CodeMirror-vscrollbar,
.CodeMirror:hover .CodeMirror-hscrollbar {
opacity: 1;
}
.container.log span.out {
color: #00207d;

/*===================================*/

.content.panel {
display: flex;
/* vertical split */
flex-direction: column;
}

.content.panel > .subpanel {
flex: 1;
position: relative;
}

.content.panel > .subpanel > div {
flex: 1;
overflow: auto;
position: absolute;
width: 100%;
height: 100%;
}

.content.panel > .editor.subpanel {
/* vertical split */
border-bottom: 1px solid #aaa;
}
.container.log span.err {
color: #861400;

/*swap to horizontal split*/
@media (max-height: 300px), (min-width: 1400px) {
.content.panel {
flex-direction: row;
}
.content.panel > .editor.subpanel {
border-bottom: none;
border-right: 1px solid #aaa;
}
}
.container.log span.agent {
color: grey;

.content.panel .editor.subpanel > div {
background: pink;
}
.content.panel .log.subpanel > div {
background: cyan;
}

.follow.icon {
position: absolute;
right: 30px;
bottom: 30px;
background: rgba(0, 0, 0, 0.1);
background: rgba(238, 238, 238, 0.9);
padding: 3px;
height: 23px;
width: 21px;
border-radius: 5px;
z-index: 5;
opacity: 0;
transition: opacity ease 0.3s;
}

/*MOBILE
@media (max-width: 736px) {
body {
flex-direction: column;
}
.controls {
max-width: 100%;
text-align: center;
border-right: none;
border-bottom: 1px solid #AAA;
}
.controls .title {
margin: 0;
}
.controls .inputs.icon {
display: inline-block;
font-size: 0.5em;
cursor: pointer;
}
.controls .inputs.form {
display: none;
}
.controls .shown.inputs.form {
display: block;
}
.controls .info.field {
text-align: center;
}
}
*/
/*HUGE*/
@media (min-width: 1440px) {
.content {
flex-direction: row;
}
.container.log {
border-top: none;
border-left: 1px solid #aaa;
}
.follow.ing.icon {
opacity: 1;
}
Loading

0 comments on commit 1f826b6

Please sign in to comment.