github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/ui/app/utils/classes/log.js (about) 1 import Ember from 'ember'; 2 import queryString from 'npm:query-string'; 3 import { task } from 'ember-concurrency'; 4 import StreamLogger from 'nomad-ui/utils/classes/stream-logger'; 5 import PollLogger from 'nomad-ui/utils/classes/poll-logger'; 6 7 const { Object: EmberObject, Evented, computed, assign } = Ember; 8 9 const MAX_OUTPUT_LENGTH = 50000; 10 11 const Log = EmberObject.extend(Evented, { 12 // Parameters 13 14 url: '', 15 params: computed(() => ({})), 16 logFetch() { 17 Ember.assert( 18 'Log objects need a logFetch method, which should have an interface like window.fetch' 19 ); 20 }, 21 22 // Read-only state 23 24 isStreaming: computed.alias('logStreamer.poll.isRunning'), 25 logPointer: null, 26 logStreamer: null, 27 28 // The top of the log 29 head: '', 30 31 // The bottom of the log 32 tail: '', 33 34 // The top or bottom of the log, depending on whether 35 // the logPointer is pointed at head or tail 36 output: computed('logPointer', 'head', 'tail', function() { 37 return this.get('logPointer') === 'head' ? this.get('head') : this.get('tail'); 38 }), 39 40 init() { 41 this._super(); 42 43 const args = this.getProperties('url', 'params', 'logFetch'); 44 args.write = chunk => { 45 let newTail = this.get('tail') + chunk; 46 if (newTail.length > MAX_OUTPUT_LENGTH) { 47 newTail = newTail.substr(newTail.length - MAX_OUTPUT_LENGTH); 48 } 49 this.set('tail', newTail); 50 this.trigger('tick', chunk); 51 }; 52 53 if (StreamLogger.isSupported) { 54 this.set('logStreamer', StreamLogger.create(args)); 55 } else { 56 this.set('logStreamer', PollLogger.create(args)); 57 } 58 }, 59 60 destroy() { 61 this.stop(); 62 this._super(); 63 }, 64 65 gotoHead: task(function*() { 66 const logFetch = this.get('logFetch'); 67 const queryParams = queryString.stringify( 68 assign(this.get('params'), { 69 plain: true, 70 origin: 'start', 71 offset: 0, 72 }) 73 ); 74 const url = `${this.get('url')}?${queryParams}`; 75 76 this.stop(); 77 let text = yield logFetch(url).then(res => res.text()); 78 79 if (text.length > MAX_OUTPUT_LENGTH) { 80 text = text.substr(0, MAX_OUTPUT_LENGTH); 81 text += '\n\n---------- TRUNCATED: Click "tail" to view the bottom of the log ----------'; 82 } 83 this.set('head', text); 84 this.set('logPointer', 'head'); 85 }), 86 87 gotoTail: task(function*() { 88 const logFetch = this.get('logFetch'); 89 const queryParams = queryString.stringify( 90 assign(this.get('params'), { 91 plain: true, 92 origin: 'end', 93 offset: MAX_OUTPUT_LENGTH, 94 }) 95 ); 96 const url = `${this.get('url')}?${queryParams}`; 97 98 this.stop(); 99 let text = yield logFetch(url).then(res => res.text()); 100 101 this.set('tail', text); 102 this.set('logPointer', 'tail'); 103 }), 104 105 startStreaming() { 106 this.set('logPointer', 'tail'); 107 return this.get('logStreamer').start(); 108 }, 109 110 stop() { 111 this.get('logStreamer').stop(); 112 }, 113 }); 114 115 export default Log; 116 117 export function logger(urlProp, params, logFetch) { 118 return computed(urlProp, params, function() { 119 return Log.create({ 120 logFetch: logFetch.call(this), 121 params: this.get(params), 122 url: this.get(urlProp), 123 }); 124 }); 125 }