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)