gpt4 book ai didi

java - 多线程 JBehave 日志记录困惑

转载 作者:行者123 更新时间:2023-12-01 09:50:04 26 4
gpt4 key购买 nike

虽然很清楚how to configure多线程jBehave运行,
我不太清楚如何处理日志困惑。

这里有哪些选项?

最佳答案

  1. 将应用程序的输出重定向到标准输出(JBehave 的输出已经存在)。注意follow=true

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.follow=true
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %-64.64C %4L | %m%n

    log4j.rootLogger=error, stdout
    log4j.logger.com.company.app.interesting.module=debug
    ...
  2. 每个线程文件输出

    @SuppressWarnings("resource")
    public class ThreadFileOutput extends PrintStream {

    private static ThreadLocal<FileOutputStream> threadOutput = new ThreadLocal<>();
    private static PrintStream stdout = System.out;
    private static PrintStream stderr = System.err;

    static {
    System.setOut(new ThreadFileOutput(stdout));
    System.setErr(new ThreadFileOutput(stderr));
    }

    public ThreadFileOutput(OutputStream out) {
    super(out);
    }

    public static void startThreadOutputRedirect(FileOutputStream stream) {
    threadOutput.set(stream);
    }

    public static void stopThreadOutputRedirect() {
    FileOutputStream stream = threadOutput.get();
    if (stream != null) {
    threadOutput.set(null);
    try {
    stream.close();
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }

    public static void forceOut(String line) {
    stdout.println(line);
    }

    public static void forceErr(String line) {
    stderr.println(line);
    }

    @Override
    public void write(byte[] b) throws IOException {
    FileOutputStream stream = threadOutput.get();
    if (stream != null) {
    try {
    stream.write(b);
    } catch (IOException e) {
    threadOutput.set(null);
    throw new RuntimeException(e);
    }
    } else {
    super.write(b);
    }
    }

    @Override
    public void write(int b) {
    FileOutputStream stream = threadOutput.get();
    if (stream != null) {
    try {
    stream.write(b);
    } catch (IOException e) {
    threadOutput.set(null);
    throw new RuntimeException(e);
    }
    } else {
    super.write(b);
    }
    }

    @Override
    public void write(byte[] buf, int off, int len) {
    FileOutputStream stream = threadOutput.get();
    if (stream != null) {
    try {
    stream.write(buf, off, len);
    } catch (IOException e) {
    threadOutput.set(null);
    throw new RuntimeException(e);
    }
    } else {
    super.write(buf, off, len);
    }
    }

    @Override
    public void flush() {
    FileOutputStream stream = threadOutput.get();
    if (stream != null) {
    try {
    stream.flush();
    } catch (IOException e) {
    threadOutput.set(null);
    throw new RuntimeException(e);
    }
    } else {
    super.flush();
    }
    }
    }
  3. 在测试前开始将线程输出重定向到文件并在测试后停止

    startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath())))); 
    stopThreadOutputRedirect();

    /**
    * JBehave to TC integration.
    */
    public class TeamCityReporter extends NullStoryReporter {

    private static final LookupTranslator ESCAPE_TABLE = new LookupTranslator(new String[][] {
    { "'", "|'" },
    { "\n", "|n" },
    { "\r", "|r" },
    { "\\u", "|0x" },
    { "|", "||" },
    { "[", "|[" },
    { "]", "|]" }
    });

    private ThreadLocal<Story> story = new ThreadLocal<>();
    private ThreadLocal<String> scenario = new ThreadLocal<>();

    @Override
    @SuppressWarnings("resource")
    public void beforeStory(Story story, boolean givenStory) {
    this.story.set(story);
    this.scenario.set(null);

    try {
    startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath()))));
    } catch (FileNotFoundException e) {
    throw new RuntimeException(e);
    }

    forceOut(format("##teamcity[testSuiteStarted name='%s']", escape(story.getPath())));
    out.println(story.getPath());

    super.beforeStory(story, givenStory);
    }

    @Override
    public void afterStory(boolean givenStory) {
    forceOut(format("##teamcity[testSuiteFinished name='%s']", escape(story.get().getPath())));
    stopThreadOutputRedirect();

    super.afterStory(givenStory);
    }

    @Override
    public void beforeScenario(String scenario) {
    this.scenario.set(scenario);

    forceOut(format("##teamcity[testStarted name='%s']", escape(scenario)));
    out.println(scenario);

    super.beforeScenario(scenario);
    }

    @Override
    public void afterScenario() {
    forceOut(format("##teamcity[testFinished name='%s']", escape(scenario.get())));

    this.scenario.set(null);
    super.afterScenario();
    }

    @Override
    public void beforeStep(String step) {
    out.println(format("\n%s\n", step));
    super.beforeStep(step);
    }

    @Override
    public void storyNotAllowed(Story story, String filter) {
    forceOut(format("##teamcity[message text='story not allowed %s' status='WARNING']", escape(story.getName())));
    out.println(format("\n(Not allowed) %s\n", story.getPath()));
    super.storyNotAllowed(story, filter);
    }

    @Override
    public void failed(String step, Throwable cause) {
    forceOut(format("##teamcity[testFailed name='%s' message='%s' details='%s']", new String[] { escape(scenario.get()), escape(getRootCauseMessage(cause)), escape(getStackTrace(cause)) }));
    out.println(format("\n(Failed) %s\n", step));
    cause.printStackTrace();
    super.failed(step, cause);
    }

    @Override
    public void pending(String step) {
    forceOut(format("##teamcity[testFailed name='%s' message='Step in PENDING state: %s']", escape(scenario.get()), escape(step)));
    out.println(format("\n(Pending) %s\n", step));
    super.pending(step);
    }

    @Override
    public void notPerformed(String step) {
    out.println(format("\n(Not performed) %s\n", step));
    super.notPerformed(step);
    }

    private static String escape(String string) {
    return ESCAPE_TABLE.translate(string);
    }
    }
  4. 打开并行 JBehave 执行

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {
    ...
    })
    public class Stories extends JUnitStories {

    @Before
    public void setUp() throws Exception {
    configuredEmbedder()
    // turn on parallel test execution
    .useExecutorService(newFixedThreadPool(30, new ThreadFactoryBuilder()
    .setDaemon(true)
    .build()));

    configuredEmbedder()
    .embedderControls()
    ...
    // don't use it this way not to produce multiThreading = true and delayed StoryReporter callbacks
    // and you will see your application logging 'for each jbehave step'
    // .useThreads(30);
    }

    @Override
    public Configuration configuration() {
    return new MostUsefulConfiguration()
    ...
    .useStoryReporterBuilder(new StoryReporterBuilder()
    ...
    .withFormats(HTML)
    .withReporters(teamCityReporter));
    }
    }

因此,每个并行测试都会有一个日志文件,其中包含测试输出和应用程序输出(仅测试运行程序线程正在执行的代码)。
额外奖励 - TeamCityReporter(JBehave 与 TC 集成)将成功地实时计算正在运行的并行测试,并在 TC GUI 上报告任何测试失败。将测试输出目录配置为 TC 工件路径以访问每个测试输出。

关于java - 多线程 JBehave 日志记录困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37654742/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com