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