github.com/ferranbt/nomad@v0.9.3-0.20190607002617-85c449b7667c/ui/app/utils/classes/log.js (about)

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