package com.yirendai.infra.cicada.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.TypeReference;
import com.yirendai.infra.cicada.entity.model.AnnotationModel;
import com.yirendai.infra.cicada.entity.model.SpanModel;
import com.yirendai.infra.cicada.entity.trace.Annotation;
import com.yirendai.infra.cicada.entity.trace.BinaryAnnotation;
import com.yirendai.infra.cicada.entity.trace.Span;
import com.yirendai.infra.cicada.repository.LogReader;
import com.yirendai.infra.cicada.util.TraceChainModelGenerator;
import com.yirendai.infra.cicada.util.progress.MessageWasher;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class LogCollectService {
@Autowired
private LogReader reader;
@Autowired
private MessageWasher washer;
@Autowired
private TraceChainModelGenerator generator;
@Autowired
private ElasticUploadService uploadTask;
private volatile boolean isInterrupt = false;
// 执行清理过程
public void finish() {
isInterrupt = true;
reader.finish();
}
// 启动任务,循环读取日志内容写入ES
public void start() {
while (true) {
if (isInterrupt) {
break;
}
process();
}
}
public void process() {
// 读取所有日志信息
final List<String> lines = reader.read();
if (lines.isEmpty()) {
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException ex) {
log.error("failed sleep interrupted, error{}", ex);
}
return;
}
// 解析日志数据,生成调用链的数据信息
final List<SpanModel> spanModels = new LinkedList<SpanModel>();
final List<AnnotationModel> annoModels = new LinkedList<AnnotationModel>();
analyze(lines, spanModels, annoModels);
// 异步上传数据到ES
uploadTask.upload(spanModels, annoModels);
}
/**
* 解析日志行.
*
* @param lines 输入参数,从日志中读取到的原始采集数据
* @param spanModels 输出参数,处理之后的SpanModel数据
* @param annoModels 输出参数,处理之后的AnnotationModel数据
*/
private void analyze(final List<String> lines, //
final List<SpanModel> spanModels, //
final List<AnnotationModel> annoModels) {
String message = null;
for (final String line : lines) {
try {
// 清洗数据
message = washer.wash(line);
// 解json
final List<Span> spans = JSON.parseObject(message, new TypeReference<List<Span>>() {});
// 生成调用链数据的存储对象
genTraceChainModel(spans, spanModels, annoModels);
} catch (JSONException ex) {
log.error("failed parse line {}, error {}", message, ex);
continue;
}
}
}
/**
* 根据日志信息生成调用链数据的存储对象(SpanModel/AnnotationModel).
*/
private void genTraceChainModel(final List<Span> spans,
final List<SpanModel> spanModels,
final List<AnnotationModel> annoModels) {
// 生成span、annotation存储对象
for (final Span span : spans) {
// 清洗annotation和binaryAnnotation信息,生成AnnotationModel信息
for (final Annotation anno : span.getAnnotations()) {
final AnnotationModel annoModel = generator.genAnnotationModel(span, anno);
annoModels.add(annoModel);
}
for (final BinaryAnnotation binAnno : span.getBinaryAnnotations()) {
final AnnotationModel annoModel = generator.genAnnotationModel(span, binAnno);
annoModels.add(annoModel);
}
// 如果是consumer端生成的span信息,继续下一循环
if (span.isConsumerSide()) {
continue;
}
// 生成SpanModel信息
final SpanModel spanModel = generator.genSpanModel(span);
if (spanModel != null) {
spanModels.add(spanModel);
}
}
}
}