Splunk Java 与 JUnit 集成
Splunk Java integration with JUnit
我制作了一个模块,可以让我使用 Java SDK 与 splunk 集成。我们通过 Maven 使用 1.2.1.0。
我的模块似乎运行良好。但是,我想围绕它进行 junit 单元测试。我创建了试图恢复最近事件的测试,但除非我睡大觉,否则我永远不会得到我刚刚输入的内容,通常是它之前的事件。我还通过索引上的事件计数(我使用测试索引)尝试了它,但也没有正确更新。有什么好的方法可以执行我可以实际验证和断言的 JUnit 测试吗?
我在此应用程序中使用 spring,因此我有一个单例服务来执行此日志记录。这是服务实现:
/*
* Copyright (c) 2015 POS Portal, Inc.
* 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
* All rights reserved.
*
* This software is the confidential and proprietary information
* of POS Portal, Inc.
*
*/
package com.posportal.splunk.impl;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Receiver;
import com.splunk.Service;
import com.splunk.ServiceArgs;
/**
* Represents a splunk logging instance. This is a spring singleton for logging.
*
* We log to the index given, so it is acceptable to have a singleton on a per index basis.
*
* Splunk configuration including index name are injected via Spring.
* @author Michael Wenk
*
*/
public class SplunkLogImpl implements SplunkLog {
private static Logger log = LoggerFactory.getLogger(SplunkLogImpl.class);
private String host;
private String user;
private String password;
private String scheme;
private String indexName;
private int port;
private boolean disabled = false;
private Service splunksvc = null;
private Receiver receiver = null;
@Override
public void logMessage(String msg, SplunkLoggingLevel level) {
if (disabled) {
log.warn("Splunk system disabled. Splunk message would be: " + msg + " on level: " + level);
} else {
if (receiver == null) {
initService();
}
String formattedMessageData = formatMessage(msg, level);
receiver.log(indexName, formattedMessageData);
}
}
private String formatMessage(String msg, SplunkLoggingLevel level) {
String fmt = "timestamp=\"%s\",level=\"%s\",data=\"%s\"";
Date now = new Date();
return String.format(fmt, now.toString(), level.toString(), msg);
}
private void initService() {
ServiceArgs loginArgs = new ServiceArgs();
loginArgs.setUsername(user);
loginArgs.setPassword(password);
loginArgs.setHost(host);
loginArgs.setScheme(scheme);
loginArgs.setPort(port);
splunksvc = Service.connect(loginArgs);
receiver = splunksvc.getReceiver();
}
public void setHost(String host) {
this.host = host;
}
public void setUser(String user) {
this.user = user;
}
public void setPassword(String password) {
this.password = password;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public void setIndexName(String indexName) {
this.indexName = indexName;
}
public void setPort(int port) {
this.port = port;
}
@Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
@Override
public boolean isDisabled() {
return disabled;
}
}
这是单元测试代码:
/*
* Copyright (c) 2015 POS Portal, Inc.
* 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
* All rights reserved.
*
* This software is the confidential and proprietary information
* of POS Portal, Inc.
*
*/
package com.posportal.splunk.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Job;
import com.splunk.JobArgs;
import com.splunk.JobArgs.ExecutionMode;
import com.splunk.Service;
import com.splunk.ServiceArgs;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:pos-splunk-test-ctx.xml")
public class SplunkTest {
//private static Logger log = LoggerFactory.getLogger(SplunkTest.class);
@Resource(name = "splunkLog")
private SplunkLog splunk;
@Resource(name = "splunkConfig")
private Map<String,String> splunkConfig;
@Test
public void testInitialMessage() throws InterruptedException
{
if (splunk.isDisabled())
{
String msg = "This is my test";
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
}
else
{
int startCount = getEventCountFromIndex();
String msg = "This is my test";
assertNotNull(splunk);
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
Service svc = getService();
assertNotNull(svc);
// Sleep for a while.
Thread.sleep(4000);
int finalCount = getEventCountFromIndex();
assertTrue(finalCount > startCount);
}
}
@Test
public void testDisabled() {
if (!splunk.isDisabled())
{
splunk.setDisabled(true);
splunk.logMessage("This is a disabled test", SplunkLoggingLevel.INFO);
// Can't assert unfortunately,
//FIXME see if I can assert using log4j itself.
}
}
private int getEventCountFromIndex() {
String searchString = "search index="+ splunkConfig.get("indexName");
JobArgs jargs = new JobArgs();
jargs.setExecutionMode(ExecutionMode.BLOCKING);
Service svc = getService();
Job j = svc.getJobs().create(searchString, jargs);
return j != null ? j.getEventCount() : -1;
}
@Test
public void testSecondMessage() throws InterruptedException
{
if (splunk.isDisabled())
{
String msg = "This is my second test";
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
}
else
{
int startCount = getEventCountFromIndex();
String msg = "This is my second test";
assertNotNull(splunk);
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
Service svc = getService();
assertNotNull(svc);
// Sleep for a while.
Thread.sleep(4000);
int finalCount = getEventCountFromIndex();
assertTrue(finalCount > startCount);
}
}
private Service getService() {
ServiceArgs loginArgs = new ServiceArgs();
loginArgs.setUsername(splunkConfig.get("user"));
loginArgs.setPassword(splunkConfig.get("password"));
loginArgs.setHost(splunkConfig.get("host"));
loginArgs.setScheme(splunkConfig.get("scheme"));
int port = Integer.parseInt(splunkConfig.get("port"));
loginArgs.setPort(port);
Service service = Service.connect(loginArgs);
return service;
}
}
如果你注意到那里的睡眠。如果我不睡觉,索引中的事件数就不会增加。不幸的是,有时 4 秒是不够的。
您看到的时间延迟是 Splunk 索引事件,这涉及写入磁盘并且可能需要时间。解决方案是,正如您已经尝试过的那样,等待 Splunk 完成。
我建议为你想尝试的次数设置一个上限,并每隔 x 秒检查一次(睡眠时间)。
在 Java 的 Splunk SDK 中(参见 SearchJobTest.java and SDKTestCase.java),我们基本上使用 assertEventuallyTrue() 方法做同样的事情:
public static boolean assertEventuallyTrue(EventuallyTrueBehavior behavior) {
int remainingTries = behavior.tries;
while (remainingTries > 0) {
boolean succeeded = behavior.predicate();
if (succeeded) {
return true;
} else {
remainingTries -= 1;
try {
Thread.sleep(behavior.pauseTime);
} catch (InterruptedException e) {}
}
}
Assert.fail(behavior.timeoutMessage);
return false;
}
我猜这是单元测试,因此您不应与 splunk 集成以进行单元测试。也许您尝试的是验收测试。
对于您的单元测试,您需要从 Splunk 中抽象出来。因此,只需从 Splunk 创建您自己的抽象层或模拟 Splunk 实现即可。
因此,您可以测试是否所有参数都得到尊重并开始创建服务,您还可以测试所有日志消息的格式是否足够好并发送到服务。
所以最后这就是所有需要做的。从 Splunk 抽象或模拟它,你会没事的。
我制作了一个模块,可以让我使用 Java SDK 与 splunk 集成。我们通过 Maven 使用 1.2.1.0。
我的模块似乎运行良好。但是,我想围绕它进行 junit 单元测试。我创建了试图恢复最近事件的测试,但除非我睡大觉,否则我永远不会得到我刚刚输入的内容,通常是它之前的事件。我还通过索引上的事件计数(我使用测试索引)尝试了它,但也没有正确更新。有什么好的方法可以执行我可以实际验证和断言的 JUnit 测试吗?
我在此应用程序中使用 spring,因此我有一个单例服务来执行此日志记录。这是服务实现:
/*
* Copyright (c) 2015 POS Portal, Inc.
* 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
* All rights reserved.
*
* This software is the confidential and proprietary information
* of POS Portal, Inc.
*
*/
package com.posportal.splunk.impl;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Receiver;
import com.splunk.Service;
import com.splunk.ServiceArgs;
/**
* Represents a splunk logging instance. This is a spring singleton for logging.
*
* We log to the index given, so it is acceptable to have a singleton on a per index basis.
*
* Splunk configuration including index name are injected via Spring.
* @author Michael Wenk
*
*/
public class SplunkLogImpl implements SplunkLog {
private static Logger log = LoggerFactory.getLogger(SplunkLogImpl.class);
private String host;
private String user;
private String password;
private String scheme;
private String indexName;
private int port;
private boolean disabled = false;
private Service splunksvc = null;
private Receiver receiver = null;
@Override
public void logMessage(String msg, SplunkLoggingLevel level) {
if (disabled) {
log.warn("Splunk system disabled. Splunk message would be: " + msg + " on level: " + level);
} else {
if (receiver == null) {
initService();
}
String formattedMessageData = formatMessage(msg, level);
receiver.log(indexName, formattedMessageData);
}
}
private String formatMessage(String msg, SplunkLoggingLevel level) {
String fmt = "timestamp=\"%s\",level=\"%s\",data=\"%s\"";
Date now = new Date();
return String.format(fmt, now.toString(), level.toString(), msg);
}
private void initService() {
ServiceArgs loginArgs = new ServiceArgs();
loginArgs.setUsername(user);
loginArgs.setPassword(password);
loginArgs.setHost(host);
loginArgs.setScheme(scheme);
loginArgs.setPort(port);
splunksvc = Service.connect(loginArgs);
receiver = splunksvc.getReceiver();
}
public void setHost(String host) {
this.host = host;
}
public void setUser(String user) {
this.user = user;
}
public void setPassword(String password) {
this.password = password;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public void setIndexName(String indexName) {
this.indexName = indexName;
}
public void setPort(int port) {
this.port = port;
}
@Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
@Override
public boolean isDisabled() {
return disabled;
}
}
这是单元测试代码:
/*
* Copyright (c) 2015 POS Portal, Inc.
* 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
* All rights reserved.
*
* This software is the confidential and proprietary information
* of POS Portal, Inc.
*
*/
package com.posportal.splunk.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Job;
import com.splunk.JobArgs;
import com.splunk.JobArgs.ExecutionMode;
import com.splunk.Service;
import com.splunk.ServiceArgs;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:pos-splunk-test-ctx.xml")
public class SplunkTest {
//private static Logger log = LoggerFactory.getLogger(SplunkTest.class);
@Resource(name = "splunkLog")
private SplunkLog splunk;
@Resource(name = "splunkConfig")
private Map<String,String> splunkConfig;
@Test
public void testInitialMessage() throws InterruptedException
{
if (splunk.isDisabled())
{
String msg = "This is my test";
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
}
else
{
int startCount = getEventCountFromIndex();
String msg = "This is my test";
assertNotNull(splunk);
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
Service svc = getService();
assertNotNull(svc);
// Sleep for a while.
Thread.sleep(4000);
int finalCount = getEventCountFromIndex();
assertTrue(finalCount > startCount);
}
}
@Test
public void testDisabled() {
if (!splunk.isDisabled())
{
splunk.setDisabled(true);
splunk.logMessage("This is a disabled test", SplunkLoggingLevel.INFO);
// Can't assert unfortunately,
//FIXME see if I can assert using log4j itself.
}
}
private int getEventCountFromIndex() {
String searchString = "search index="+ splunkConfig.get("indexName");
JobArgs jargs = new JobArgs();
jargs.setExecutionMode(ExecutionMode.BLOCKING);
Service svc = getService();
Job j = svc.getJobs().create(searchString, jargs);
return j != null ? j.getEventCount() : -1;
}
@Test
public void testSecondMessage() throws InterruptedException
{
if (splunk.isDisabled())
{
String msg = "This is my second test";
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
}
else
{
int startCount = getEventCountFromIndex();
String msg = "This is my second test";
assertNotNull(splunk);
splunk.logMessage(msg, SplunkLoggingLevel.INFO);
Service svc = getService();
assertNotNull(svc);
// Sleep for a while.
Thread.sleep(4000);
int finalCount = getEventCountFromIndex();
assertTrue(finalCount > startCount);
}
}
private Service getService() {
ServiceArgs loginArgs = new ServiceArgs();
loginArgs.setUsername(splunkConfig.get("user"));
loginArgs.setPassword(splunkConfig.get("password"));
loginArgs.setHost(splunkConfig.get("host"));
loginArgs.setScheme(splunkConfig.get("scheme"));
int port = Integer.parseInt(splunkConfig.get("port"));
loginArgs.setPort(port);
Service service = Service.connect(loginArgs);
return service;
}
}
如果你注意到那里的睡眠。如果我不睡觉,索引中的事件数就不会增加。不幸的是,有时 4 秒是不够的。
您看到的时间延迟是 Splunk 索引事件,这涉及写入磁盘并且可能需要时间。解决方案是,正如您已经尝试过的那样,等待 Splunk 完成。
我建议为你想尝试的次数设置一个上限,并每隔 x 秒检查一次(睡眠时间)。
在 Java 的 Splunk SDK 中(参见 SearchJobTest.java and SDKTestCase.java),我们基本上使用 assertEventuallyTrue() 方法做同样的事情:
public static boolean assertEventuallyTrue(EventuallyTrueBehavior behavior) {
int remainingTries = behavior.tries;
while (remainingTries > 0) {
boolean succeeded = behavior.predicate();
if (succeeded) {
return true;
} else {
remainingTries -= 1;
try {
Thread.sleep(behavior.pauseTime);
} catch (InterruptedException e) {}
}
}
Assert.fail(behavior.timeoutMessage);
return false;
}
我猜这是单元测试,因此您不应与 splunk 集成以进行单元测试。也许您尝试的是验收测试。
对于您的单元测试,您需要从 Splunk 中抽象出来。因此,只需从 Splunk 创建您自己的抽象层或模拟 Splunk 实现即可。
因此,您可以测试是否所有参数都得到尊重并开始创建服务,您还可以测试所有日志消息的格式是否足够好并发送到服务。
所以最后这就是所有需要做的。从 Splunk 抽象或模拟它,你会没事的。