绝大多数项目在后台管理中都有日志管理。以前的日志信息是存储在MySQL中,日志随着项目运行时间会越来越多,一直存储在MySQL会导致查询降低。现在的日志信息通过ELK技术栈进行操作。存储在Elasticsearch中,可以更好的分析日志内容及更快查询效率。
给定简单需求: 搭建日志系统,提供查询Elasticsearch中日志信息的接口。
搭建最基本的环境,实现需求,没有考虑Spring Cloud相关环境,如果考虑Spring Cloud还需要配置Eureka等信息。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
在resources下新建application.yml配置文件。 配置Elasticsearch相关配置信息。
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.8.140:9300
根据kibana中查看到日志信息可以得出看出,除了message是类类型,里面包含一些其他属性外,其他的属性都是简单类型属性。
@Data
@Document(indexName = "test_log",type = "doc")
public class Log {
@Id
private String id;
@Field(type= FieldType.Text)
private String host;
@Field(type= FieldType.Text)
private String message;
@Field(type= FieldType.Long)
private Long port;
@Field(type = FieldType.Date)
@JsonProperty("@timestamp")
private Date timestamp;
@Field(type = FieldType.Text)
@JsonProperty("@version")
private String version;
}
新建com.service.LogService及实现类
public interface LogService {
List<Log> selectByPage(int page,int size);
}
@Service
public class LogServiceImpl implements LogService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public List<Log> selectByPage(int page, int size) {
SearchQuery sq = new NativeSearchQuery(QueryBuilders.matchAllQuery());
sq.setPageable(PageRequest.of(page-1,size));
return elasticsearchTemplate.queryForList(sq,Log.class);
}
}
新建com.controller.LogController
@Controller
public class LogController {
@Autowired
private LogService logService;
@RequestMapping("/page")
@ResponseBody
public List<Log> showPage(int page,int size){
return logService.selectByPage(page,size);
}
}
上面搭建日志系统时完成了从ES中取出日志信息的功能。但是所有真实日志的信息都存储在String message中。默认没有做任何处理,处理过程应该交给客户端做字符串JSON转换,最终显示在页面中。如果在服务器端必须要获取日志内容(message)或日志级别(level)或线程名(thread_name)等日志信息就需要在服务器端做JSON转换。 下面代码演示如果在服务器端把String message转换为实体类并获取日志信息的步骤。
所有的操作都在上面代码基础进行操作。
新建com.pojo.Message /**
@Data
public class Message {
@JsonProperty("@timestamp")
private Date timestamp;
@JsonProperty("@version")
private String version;
private String message;
private String logger_name;
private String thread_name;
private String level;
private Integer level_value;
}
修改com.bjsxt.pojo.Log。添加一个属性
@Data
@Document(indexName = "test_log",type = "doc")
public class Log {
@Id
private String id;
@Field(type = FieldType.Text)
private String host;
@Field(type=FieldType.Text)
private String message;
@Field(type=FieldType.Integer)
private Integer port;
@Field(type=FieldType.Text)
@JsonProperty("@version")
private String version;
@Field(type=FieldType.Date)
@JsonProperty("@timestamp")
private Date timestamp;
// 这个属性没有和Elasticsearch中属性对应的。所以没有@Field注解
// 主要目的就是为了返回Log时包含转换好的Message信息。
// 为了演示这么做的。绝大多数情况把字符串message返回给客户端,由客户端做json转换。
private Message msgPojo;
}
修改com.bjsxt.service.impl.LogServiceImpl。 使用Jacksong把Log类中message转换为Message类型,并设置到Log类中msgPojo属性内容。 转换完成后的Message类型中就存储了日志所有相关信息。通过操作Message获取所有的日志内容。
@Service
public class LogServiceImpl implements LogService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public List<Log> selectByPage(int page, int size) {
ObjectMapper objectMapper = new ObjectMapper();
SearchQuery sq = new NativeSearchQuery(QueryBuilders.matchAllQuery());
sq.setPageable(PageRequest.of(page-1,size));
List<Log> list = elasticsearchTemplate.queryForList(sq, Log.class);
try {
for(Log log : list){
Message msg = objectMapper.readValue(log.getMessage(), Message.class);
System.out.println("在Java代码获取日志内容的实现方案:"+msg.getMessage());
log.setMsgPojo(msg);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return list;
}
}