/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gobblin.runtime.plugins.email;
import java.net.URI;
import org.apache.commons.mail.EmailException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import gobblin.configuration.ConfigurationKeys;
import gobblin.runtime.JobState.RunningState;
import gobblin.runtime.api.GobblinInstanceDriver;
import gobblin.runtime.api.GobblinInstancePlugin;
import gobblin.runtime.api.GobblinInstancePluginFactory;
import gobblin.runtime.api.JobExecutionDriver;
import gobblin.runtime.api.JobExecutionState;
import gobblin.runtime.api.JobLifecycleListener;
import gobblin.runtime.api.JobSpec;
import gobblin.runtime.api.JobSpecSchedule;
import gobblin.runtime.instance.StandardGobblinInstanceDriver;
import gobblin.runtime.instance.plugin.BaseIdlePluginImpl;
import gobblin.util.ConfigUtils;
import gobblin.util.EmailUtils;
/**
* A plugin that attaches an email notification listener to a {@link GobblinInstanceDriver}. The listener sends emails
* on job completion
*/
public class EmailNotificationPlugin extends BaseIdlePluginImpl {
private static final Logger LOGGER = LoggerFactory.getLogger(EmailNotificationPlugin.class);
/**
* An instance level setting to disable email notifications to all job launched by an instance
*/
public static final String EMAIL_NOTIFICATIONS_DISABLED_KEY = StandardGobblinInstanceDriver.INSTANCE_CFG_PREFIX
+ ".emailNotifications.disabled";
public static final boolean EMAIL_NOTIFICATIONS_DISABLED_DEFAULT = false;
public EmailNotificationPlugin(GobblinInstanceDriver instance) {
super(instance);
}
@Override
protected void startUp() throws Exception {
instance.registerJobLifecycleListener(new EmailNotificationListerner());
LOGGER.info("Started Email Notification Plugin");
}
public static class Factory implements GobblinInstancePluginFactory {
@Override
public GobblinInstancePlugin createPlugin(GobblinInstanceDriver instance) {
return new EmailNotificationPlugin(instance);
}
}
/**
* Sends emails when job completes with FAILED, COMMITED or CANCELLED state.
* Emails sent when job fails with FAILED status can be turned off by setting {@link ConfigurationKeys#ALERT_EMAIL_ENABLED_KEY} to false
* Emails sent when job completes with COMMITTED/CANCELLED status can be turned off by
* setting {@link ConfigurationKeys#NOTIFICATION_EMAIL_ENABLED_KEY} to false
*/
private static class EmailNotificationListerner implements JobLifecycleListener {
@Override
public void onStatusChange(JobExecutionState state, RunningState previousStatus, RunningState newStatus) {
if (newStatus.isDone() && !previousStatus.isDone()) {
boolean alertEmailEnabled =
ConfigUtils.getBoolean(state.getJobSpec().getConfig(), ConfigurationKeys.ALERT_EMAIL_ENABLED_KEY, false);
boolean notificationEmailEnabled =
ConfigUtils.getBoolean(state.getJobSpec().getConfig(), ConfigurationKeys.NOTIFICATION_EMAIL_ENABLED_KEY,
false);
// Send failure emails
if (alertEmailEnabled && newStatus.isFailure()) {
try {
LOGGER.info("Sending job failure email for job: {}", state.getJobSpec().toShortString());
EmailUtils.sendJobFailureAlertEmail(state.getJobSpec().toShortString(),
getEmailBody(state, previousStatus, newStatus), 1,
ConfigUtils.configToState(state.getJobSpec().getConfig()));
} catch (EmailException ee) {
LOGGER.error("Failed to send job failure alert email for job " + state.getJobSpec().toShortString(), ee);
}
return;
}
// Send job completion emails
if (notificationEmailEnabled && (newStatus.isCancelled() || newStatus.isSuccess())) {
try {
LOGGER.info("Sending job completion email for job: {}", state.getJobSpec().toShortString());
EmailUtils.sendJobCompletionEmail(state.getJobSpec().toShortString(),
getEmailBody(state, previousStatus, newStatus), newStatus.toString(),
ConfigUtils.configToState(state.getJobSpec().getConfig()));
} catch (EmailException ee) {
LOGGER.error("Failed to send job completion notification email for job "
+ state.getJobSpec().toShortString(), ee);
}
}
}
}
private static String getEmailBody(JobExecutionState state, RunningState previousStatus, RunningState newStatus) {
return new StringBuilder().append("RunningState: ").append(newStatus.toString()).append("\n")
.append("JobExecutionState: ").append(state.getJobSpec().toLongString()).append("\n")
.append("ExecutionMetadata: ").append(state.getExecutionMetadata()).toString();
}
@Override
public void onAddJob(JobSpec addedJob) {
}
@Override
public void onDeleteJob(URI deletedJobURI, String deletedJobVersion) {
}
@Override
public void onUpdateJob(JobSpec updatedJob) {
}
@Override
public void onJobScheduled(JobSpecSchedule jobSchedule) {
}
@Override
public void onJobUnscheduled(JobSpecSchedule jobSchedule) {
}
@Override
public void onJobTriggered(JobSpec jobSpec) {
}
@Override
public void onStageTransition(JobExecutionState state, String previousStage, String newStage) {
}
@Override
public void onMetadataChange(JobExecutionState state, String key, Object oldValue, Object newValue) {
}
@Override
public void onJobLaunch(JobExecutionDriver jobDriver) {
}
}
}