rancher 容器日志组件分析
        【摘要】 
                    \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×tamps=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)