rancher 容器日志组件分析

举报
拿我格子衫来 发表于 2022/03/18 00:19:28 2022/03/18
【摘要】 \app\components\container-logs\template.hbs 使用的websock   template.hbs <h2> <i class="icon icon-file"></i> {{t 'containerLogs.title'}} {{#if ...

\app\components\container-logs\template.hbs

使用的websock

 

template.hbs


      <h2>
       <i class="icon icon-file"></i> {{t 'containerLogs.title'}}
        {{#if displayName}}
          {{displayName}}
        {{else if (gt instance.containers.length 1)}}
         <div class="container-select">
            {{new-select
              classNames="form-control"
              optionValuePath="name"
              optionLabelPath="name"
              content=instance.containers
              value=containerName
            }}
         </div>
        {{else}}
           {{containerName}}
        {{/if}}
       <div class="console-status text-muted pull-right">{{t (concat 'containerLogs.status.' status)}}</div>
      </h2>
      {{#if showProtip}}
       <div class="protip">
            {{t 'containerLogs.protip' key=alternateLabel}}
       </div>
      {{/if}}
      <pre class="log-body {{if wrapLines 'wrap-lines'}}">
      </pre>
      {{yield}}
      <div class="footer-actions">
       <div class="checkbox pt-10 text-left" style="position: absolute; top: -2px">
         <label class="block">
            {{input type="checkbox" checked=wrapLines}}
            {{t 'containerLogs.wrapLines'}}
         </label>
         <label class="block">
            {{input type="checkbox" checked=isPrevious}}
            {{t 'containerLogs.previous'}}
         </label>
       </div>
       <button {{action "scrollToTop"}} class="btn bg-default">{{t 'containerLogs.scrollTop'}}</button>
       <button {{action "followLog"}} class="btn bg-default scroll-bottom">{{t 'containerLogs.scrollBottom'}}</button>
       <button {{action "download"}} class="btn bg-default">{{t 'containerLogs.download'}}</button>
       <button {{action "clear"}} class="btn bg-default">{{t 'containerLogs.clear'}}</button>
       <button {{action "cancel"}} class="btn bg-primary">{{t 'generic.closeModal'}}</button>
      </div>
  
 

 

 

 

component.js


      import { next } from '@ember/runloop';
      import { set, setProperties, get, observer } from '@ember/object';
      import { inject as service } from '@ember/service';
      import Component from '@ember/component';
      import Util from 'ui/utils/util';
      import { alternateLabel } from 'ui/utils/platform';
      import layout from './template';
      import C from 'ui/utils/constants';
      import { downloadFile } from 'shared/utils/download-files';
      import $ from 'jquery';
      import { on } from '@ember/object/evented';
      const LINES = 500;
      var AnsiUp = null;
      export default Component.extend({
       scope: service(),
       prefs: service(),
        layout,
       instance:       null,
        alternateLabel,
       showProtip:     true,
       classNames:    'container-log',
       status:         'connecting',
       containerName:  null,
       socket:         null,
       wrapLines:      null,
       isFollow:       true,
       followTimer:    null,
       isPrevious:     false,
       init() {
         this._super(...arguments);
         if (AnsiUp) {
           this._bootstrap();
          } else {
           import('ansi_up').then( (module) => {
             AnsiUp = module.default;
             this._bootstrap();
            });
          }
        },
       didInsertElement() {
         this._super();
         next(this, () => {
           const body = $('.log-body');
           let lastScrollTop = 0;
            body.scroll(() => {
             const scrollTop = body[0].scrollTop;
             if ( lastScrollTop >  scrollTop ) {
               set(this, 'isFollow', false);
              }
              lastScrollTop = scrollTop;
            });
           var btn = $('.scroll-bottom')[0]; // eslint-disable-line
           if ( btn ) {
              btn.focus();
            }
          });
        },
       willDestroyElement() {
         clearInterval(get(this, 'followTimer'));
         this.disconnect();
         this._super();
        },
       actions: {
         download() {
           const ignore = function(el, sel){
             return el.clone().find( sel || '>*' ).remove().end();
            };
           const log    = $('.log-body').children('.log-msg');
           let stripped = '';
            log.each((i, e) => {
              stripped += `${ ignore($(e), 'span').text() } \n`;
            });
           downloadFile('container.log', stripped);
          },
         cancel() {
           this.disconnect();
           if (this.dismiss) {
             this.dismiss();
            }
          },
         clear() {
           var body = $('.log-body')[0];
           if (body) {
              body.innerHTML = '';
              body.scrollTop = 0;
            }
          },
         scrollToTop() {
            $('.log-body').animate({ scrollTop: '0px' });
          },
         followLog() {
           set(this, 'isFollow', true);
           this.send('scrollToBottom');
          },
         scrollToBottom() {
           var body = $('.log-body');
            body.stop().animate({ scrollTop: `${ body[0].scrollHeight + 1000 }px` });
          },
        },
       wrapLinesDidChange: observer('wrapLines', function() {
         set(this, `prefs.${ C.PREFS.WRAP_LINES }`, get(this, 'wrapLines'));
        }),
       watchReconnect: on('init', observer('containerName', 'isPrevious', function() {
         this.disconnect();
         this.send('clear');
         if (this.containerName) {
           this.exec();
          }
        })),
       _bootstrap() {
         setProperties(this, {
           wrapLines:     !!get(this, `prefs.${ C.PREFS.WRAP_LINES }`),
           containerName: get(this, 'containerName') || get(this, 'instance.containers.firstObject.name'),
          });
         this._initTimer();
        },
       _initTimer() {
         const followTimer = setInterval(() => {
           if ( get(this, 'isFollow') ) {
             this.send('scrollToBottom');
            }
          }, 1000);
         set(this, 'followTimer', followTimer);
        },
       exec() {
         var instance = get(this, 'instance');
         const clusterId = get(this, 'scope.currentCluster.id');
         const namespaceId = get(instance, 'namespaceId');
         const podName = get(instance, 'name');
         const containerName = get(this, 'containerName');
         const scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
         let url = `${ scheme }${ window.location.host }/k8s/clusters/${ clusterId }/api/v1/namespaces/${ namespaceId }/pods/${ podName }/log`;
          url += `?container=${ encodeURIComponent(containerName) }&tailLines=${ LINES }&follow=true&timestamps=true&previous=${ get(this, 'isPrevious') }`;
         this.connect(url);
        },
       connect(url) {
         var socket = new WebSocket(url, 'base64.binary.k8s.io');
         set(this, 'socket', socket);
         var body = null;
         set(this, 'status', 'initializing');
          socket.onopen = () => {
           set(this, 'status', 'connected');
          };
          socket.onmessage = (message) => {
            body = $('.log-body')[0];
           let ansiup = new AnsiUp;
           set(this, 'status', 'connected');
           const data = AWS.util.base64.decode(message.data).toString();
           let html = '';
            data.trim().split(/\n/)
              .filter((line) => line)
              .forEach((line) => {
               var match = line.match(/^\[?([^ \]]+)\]?\s?/);
               var dateStr = '';
               var msg = '';
               if (match && this.isDate(new Date(match[1]))) {
                 var date = new Date(match[1]);
                  msg = line.substr(match[0].length);
                  dateStr = `<span class="log-date">${ Util.escapeHtml(date.toLocaleDateString()) } ${ Util.escapeHtml(date.toLocaleTimeString()) } </span>`;
                } else {
                  msg = line;
                }
               // @@TODO@@ - 10-13-17 - needed to remove the escaping here because it was being double escaped but double verify that its acutally being escaped
                html += `<div class="log-msg log-combined">${
       dateStr
       }${ ansiup.ansi_to_html(msg)
       }</div>`
              });
            body.insertAdjacentHTML('beforeend', html);
          };
          socket.onclose = () => {
           if (this.isDestroyed || this.isDestroying) {
             return;
            }
           set(this, 'status', 'disconnected');
          };
        },
       disconnect() {
         set(this, 'status', 'closed');
         var socket = get(this, 'socket');
         if (socket) {
            socket.close();
           set(this, 'socket', null);
          }
        },
       isDate(date) {
         return new Date(date) !== 'Invalid Date' && !isNaN(new Date(date))
        },
      });
  
 

 

文章来源: fizzz.blog.csdn.net,作者:拿我格子衫来,版权归原作者所有,如需转载,请联系作者。

原文链接:fizzz.blog.csdn.net/article/details/108662784

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。