I've bumped into a following problem with Azure Diagnostic Monitor:
When I create a new AppDomain in OnStart() event in WorkerRole entry point the diagnostics works only in the parent AppDomain. I've tried initializing Diagnostics Monitor in the child AppDomain but it doesn't help. (Traces are collected only from the parent domain)
Example repro code:
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
// This is a sample worker implementation. Replace with your logic.
InitializeDiagnostics();
Trace.TraceInformation("WorkerRole1 entry point called", "Information");
while (true)
{
Thread.Sleep(10000);
Trace.TraceInformation("Parent domain working", "Information");
}
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
InitializeDiagnostics();
var setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
var newDomain = System.AppDomain.CreateDomain("NewApplicationDomain",null, setup);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.GlobalAssemblyCache))
{
newDomain.Load(assembly.GetName());
}
newDomain.Load(typeof (Worker).Assembly.FullName);
var worker = newDomain.CreateInstanceAndUnwrap(this.GetType().Assembly.FullName, typeof (Worker).FullName) as Worker;
worker.DoWork();
return base.OnStart();
}
public void InitializeDiagnostics()
{
var roleInstanceDiagnosticManager = new RoleInstanceDiagnosticManager(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"),
RoleEnvironment.DeploymentId,
RoleEnvironment.CurrentRoleInstance
.Role.Name,
RoleEnvironment.CurrentRoleInstance.Id);
var dmc = roleInstanceDiagnosticManager.GetCurrentConfiguration();
var dictionaryConfiguration = new DirectoryConfiguration();
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", dmc);
}
}
public class Worker : MarshalByRefObject
{
public void DoWork()
{
new Task(() =>
{
while (true)
{
Thread.Sleep(1000);
Trace.TraceInformation(AppDomain.CurrentDomain.FriendlyName + " Worker working...", "Information");
}
}).Start();
}
}
}
App config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace>
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
</system.diagnostics>
</configuration>
Expected output:
Lots of logged messages:
"{Domain Name} Wokrer working..."
Some
"Parent domain working"
Actual output:
"Parent domain working"
I'm using Azure SDK 2.0. Have any of you came across a similar issue ?
Ok, finally solved it. Upgrading Azure SDK to 2.3 did the thing... It's interesting that messages still doesn't appear in Compute emulator console, but after upgrade they are correctly logged to WADLog table.
Related
I couldn't find any information on how to do it. Basically FluentFTP is using System.Diagnostics to log their messages.
FluentFtp expose the following static method:
FtpTrace.AddListener(TraceListener listener);
However I don't know if there is any way to implement (or use existing implementation, which?) TraceListener in the way it relays everything to log4net engine.
Any hints or ideas?
Thanks, Radek
You can attach a listener to the OnLogEvent method that FluentFTP exposes.
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static void UploadFTP(FileInfo localFile, string remoteFileLocation, string remoteServer, NetworkCredential credentials)
{
FtpClient client = new FtpClient(remoteServer, credentials);
client.RetryAttempts = 3;
client.OnLogEvent = OnFTPLogEvent;
client.Connect();
if (!client.UploadFile(localFile.FullName, remoteFileLocation, FtpExists.Overwrite, false, FtpVerify.Retry | FtpVerify.Throw))
{
throw new Exception($"Could not Upload File {localFile.Name}. See Logs for more information");
}
}
private static void OnFTPLogEvent(FtpTraceLevel ftpTraceLevel, string logMessage)
{
switch (ftpTraceLevel)
{
case FtpTraceLevel.Error:
Log.Error(logMessage);
break;
case FtpTraceLevel.Verbose:
Log.Debug(logMessage);
break;
case FtpTraceLevel.Warn:
Log.Warn(logMessage);
break;
case FtpTraceLevel.Info:
default:
Log.Info(logMessage);
break;
}
}
The method OnFTPLogEvent will be called every-time the OnLogEvent action will be called allowing you to extend any logging you have already built into your application.
Basically FluentFTP is using System.Diagnostics.TraceListener so in order to make it logging to your log4net log you need to write your own simple class that would redirect logs to log4net logger. Like the following:
using System.Diagnostics;
using log4net;
namespace YourApp.Logging
{
public class Log4NetTraceListener : TraceListener
{
private readonly ILog _log;
public Log4NetTraceListener(string provider)
{
_log = LogManager.GetLogger(provider);
}
public override void Write(string message)
{
if(_log == null)
return;
if(!string.IsNullOrWhiteSpace(message))
_log.Info(message);
}
public override void WriteLine(string message)
{
if(_log == null)
return;
if (!string.IsNullOrWhiteSpace(message))
_log.Info(message);
}
}
}
Then, in your app.config file add the following entry:
<system.diagnostics>
<trace autoflush="true"></trace>
<sources>
<source name="FluentFTP">
<listeners>
<clear />
<add name="FluentLog" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="FluentLog" type="YourApp.Logging.Log4NetTraceListener, YourApp" initializeData="FluentLog" />
</sharedListeners>
</system.diagnostics>
That should enable FluentFtp logs and merge it with your application log4net log.
On some machines (probably only on Windows 7 and 2008 R2 but not on Windows 10) I have problem using SemanticLogging. When I run it I'm receiving fallowing output:
Event Trace Session prefix: Microsoft-SemanticLogging-Etw
Sink name: ConsoleEventSink
Event sources:
Name: 8943bf09-be18-551a-efe5-612ee62ded5e
Performance, Level: LogAlways, MatchAnyKeyword: None
Sink name: PerformaceSINK
Event sources:
Name: 8943bf09-be18-551a-efe5-612ee62ded5e
Performance, Level: LogAlways, MatchAnyKeyword: None
Service started.
Press enter to end ...
ERROR: Exception in Command Processing for EventSource Performance: Object
reference not set to an instance of an object.;
All that happens in specific scenerio:
I'm starting process which writes Events
then I run SemanticLogging-svc.exe -c
after few moments error occurs
But when I change order and first start SemanticLogging-svc.exe and after that I run "event writer", everything goes how it should.
But when I setup all as described in first scenerio and after error I will try to collect data using PerfView magic happens and SemanticLogging starts collecting data.
Using PerfView I have checked Microsoft-SemanticLogging-Etw source but nothing there.
SemanticLogging-svc.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/practices/2013/entlib/semanticlogging/etw"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.microsoft.com/practices/2013/entlib/semanticlogging/etw SemanticLogging-svc.xsd">
<traceEventService />
<sinks>
<consoleSink name="ConsoleEventSink">
<sources>
<eventSource name="PerformanceEventSource" level="LogAlways" />
</sources>
<customEventTextFormatter type="ServiceTelemetry.EventFormatter.CsvEventFormatter, ServiceTelemetry"/>
</consoleSink>
<rollingFlatFileSink
name="PerformanceEventSourceSINK"
fileName=".\logs\%ComputerName%_Performance.log"
rollFileExistsBehavior="Increment"
rollInterval="Midnight"
timeStampPattern="yyyyMMdd">
<sources>
<eventSource name="PerformanceEventSource" level="LogAlways" />
</sources>
<customEventTextFormatter type="ServiceTelemetry.EventFormatter.CsvEventFormatter, ServiceTelemetry"/>
</rollingFlatFileSink>
</sinks>
</configuration>
EventFormatter:
namespace ServiceTelemetry.EventFormatter
{
public class CsvEventFormatter : IEventTextFormatter
{
public void WriteEvent(EventEntry eventEntry, TextWriter writer)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < eventEntry.Payload.Count; i++)
{
sb.AppendFormat("{0};", eventEntry.Payload[i]);
}
writer.WriteLine(sb.ToString());
}
}
}
EventSource:
namespace ServiceTelemetry.EventSources
{
[EventSource(Name = "Performance")]
public sealed class PerformanceEventSource : EventSource
{
[Event(1, Level = EventLevel.LogAlways, Task = TaskCodes.GetResource, Opcode = OperationCodes.Compleated)]
public void GetResourceSuccess(string Session, string ResourceName, long ElapsedMilliseconds)
{
if (IsEnabled())
{
WriteEvent(1, Session, ResourceName, ElapsedMilliseconds);
}
}
public static PerformanceEventSource Log = new PerformanceEventSource();
private PerformanceEventSource()
{
}
}
}
It was necessary to install manifest first, then you can start your EventWriter and you can collect data any time you start SematicLogger.
Unfortunately system throws error but for now I'm good with that.
EventSource .net 4.0 GenerateManifest
I'm developing an Azure WorkerRole(). In the Compute Emulator console, I see all Trace.WriteLine() messages, but only those generated in OnStart() seem to be persisted into storage.
My ServiceConfiguration.Local.csfg has:
<Role name="MyWorkerRole">
<Instances count="1" />
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
</ConfigurationSettings>
</Role>
My WorkerRole.cs has:
public override void Run() {
Trace.WriteLine("Called from Run(), where does this trace go???", "Information");
// ... SNIP ...
}
public override bool OnStart() {
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
DiagnosticMonitor.Start("DiagnosticsConnectionString", dmc);
Trace.WriteLine("This trace appears in WADLogsTable", "Information");
return base.OnStart();
}
That looks correct - I wonder why you don't see anything. I wonder if Start is ignoring your config changes somehow. Here is some code I have used that will transfer the trace logs (I know this works):
private static void EnableDiagnostics(int transferTime)
{
string wadConnectionString = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue(wadConnectionString));
RoleInstanceDiagnosticManager roleInstanceDiagnosticManager = storageAccount.CreateRoleInstanceDiagnosticManager(RoleEnvironment.DeploymentId, RoleEnvironment.CurrentRoleInstance.Role.Name, RoleEnvironment.CurrentRoleInstance.Id);
DiagnosticMonitorConfiguration config = roleInstanceDiagnosticManager.GetCurrentConfiguration();
if (config == null)
{
config = DiagnosticMonitor.GetDefaultInitialConfiguration();
}
config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(transferTime);
config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Undefined;
CrashDumps.EnableCollection(true);
roleInstanceDiagnosticManager.SetCurrentConfiguration(config);
}
I am trying to create a custom workflow activity which gives me the list of recipients that I am storing in list. But once I deploy and start the workflow nothing is happening, not even log messages are coming. So i tried to debug the code but breakpoints are not set and I am getting the error "The Breakpoint will not currently be hit. No symbols have been loaded for this document." Can anyone please help me to deal with this issue.
Below are the steps I have followed in creating this activity.
1. created a workflow activity library.
(please find my code file attached)
added .dll to GAC
updated web.config and WSS.actions files.
Now I see the action in designer, so i have created a workflow using designer.
strted the workflow manually on an item.
Here nothing is happening, not even an error. Please let me know if you need any further information.
Please find the code below.
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using System.Diagnostics;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
namespace CustomWorkflowActivityLibrary
{
public partial class CustomWorkflowActivity: SequenceActivity
{
SPList _list;
private EventLog _log;
SPFieldUserValueCollection objUserFieldValueCol;
string semailsettingKeyword1;
string semailsettingKeyword2;
public CustomWorkflowActivity()
{
InitializeComponent();
}
public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(CustomWorkflowActivity));
[DescriptionAttribute("__Context")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
get { return ((WorkflowContext)(base.GetValue(CustomWorkflowActivity.__ContextProperty))); }
set { base.SetValue(CustomWorkflowActivity.__ContextProperty, value); }
}
public static DependencyProperty ListIdProperty = DependencyProperty.Register("ListId", typeof(string), typeof(CustomWorkflowActivity));
[DescriptionAttribute("ListId")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public string ListId
{
get { return ((string)(base.GetValue(CustomWorkflowActivity.ListIdProperty))); }
set { base.SetValue(CustomWorkflowActivity.ListIdProperty, value); }
}
public static DependencyProperty ListItemProperty = DependencyProperty.Register("ListItem", typeof(int), typeof(CustomWorkflowActivity));
[DescriptionAttribute("ListItem")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public int ListItem
{
get { return ((int)(base.GetValue(CustomWorkflowActivity.ListItemProperty))); }
set { base.SetValue(CustomWorkflowActivity.ListItemProperty, value); }
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
_log = new EventLog("Add Description");
_log.Source = "Share Point Workflows";
try
{
//Execute method as a elevated method
SPSecurity.CodeToRunElevated elevatedExecuteMethod = new SPSecurity.CodeToRunElevated(ExecuteMethod);
SPSecurity.RunWithElevatedPrivileges(elevatedExecuteMethod);
}
catch (Exception ex)
{
_log.WriteEntry("Error" + ex.Message.ToString(), EventLogEntryType.Error);
}
return ActivityExecutionStatus.Closed;
}
private void ExecuteMethod()
{
try
{
//retrieveing the Site object
SPSite _site = new SPSite(__Context.Site.Url);
//retrieveing the Web object
SPWeb _web = (SPWeb)(__Context.Web);
//retrieveing the list object
_list = _web.Lists[new Guid(this.ListId)];
//retrieveing the list item object
SPListItem _listItem = _list.GetItemById(this.ListItem);
_site.AllowUnsafeUpdates = true;
_web.AllowUnsafeUpdates = true;
string semailsubject = _listItem["E-Mail Subject"].ToString();
string semailfrom = _listItem["emailfrom"].ToString();
_log = new EventLog("get vendor info");
_log.WriteEntry("semailsubject");
_log.WriteEntry("semailfrom");
/* _listItem.Update();
_list.Update();
_site.AllowUnsafeUpdates = false;
_web.AllowUnsafeUpdates = false;*/
using (SPSite mysite = new SPSite("http://dlglobaltest.dl.com/Admin/IT/Application%20Development%20Group/LibraryEmailDistribution"))
{
using (SPWeb myweb = mysite.OpenWeb())
{
SPList settingsList = myweb.Lists["EmailDistributionSettings"];
SPQuery oQuery = new SPQuery();
oQuery.Query = "<Where><Eq><FieldRef Name='Sender' /><Value Type='Text'>" + semailfrom + "</Value></Eq></Where>";
SPListItemCollection ColListItems = settingsList.GetItems(oQuery);
foreach (SPListItem oListItem in ColListItems)
{
semailsettingKeyword1 = oListItem["Keyword1"].ToString();
semailsettingKeyword2 = oListItem["Keyword2"].ToString();
//SPFieldUserValue objUserFieldValue = new SPFieldUserValue(myweb, oListItem["Recipients"].ToString());
if ((semailsubject.Contains(semailsettingKeyword1)) || (semailsubject.Contains(semailsettingKeyword2)))
{
objUserFieldValueCol = new SPFieldUserValueCollection(myweb, oListItem["Recipients"].ToString());
_log = new EventLog(objUserFieldValueCol.ToString());
}
}
}
}
}
catch (Exception ex)
{ }
}
}
}
Web.Config:
<authorizedType Assembly="CustomWorkflowActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a95e146fc1062337" Namespace="CustomWorkflowActivityLibrary" TypeName="*" Authorized="True" />
WSS.Actions:
<Action Name="Get Recipients"
ClassName="CustomWorkflowActivityLibrary.CustomWorkflowActivity"
Assembly="CustomWorkflowActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a95e146fc1062337"
AppliesTo="all" Category="Custom">
<RuleDesigner Sentence="Get Recipients for %1 ">
<FieldBind Field="ListId,ListItem" Text="this list" Id="1" DesignerType="ChooseListItem" />
</RuleDesigner>
<Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />
<Parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />
</Parameters>
</Action>
Thanks,
I am not sure if this will help but you could try changing the following line in your code from this:
SPSecurity.RunWithElevatedPrivileges(elevatedExecuteMethod);
To this:
SPSecurity.RunWithElevatedPrivileges(delegate(){
ExecuteMethod();
});
Another shot-in-the-dark reply:
Try changing the class you're inheriting ( http://msdn.microsoft.com/en-us/library/ms173149(v=VS.80).aspx ) from SequenceActivity to Activity (SequenceActivity inherits from CompositeActivity, which itself inherits from Activity. See: http://msdn.microsoft.com/en-us/library/system.workflow.activities.sequenceactivity(v=VS.90).aspx )
If that doesn't work, try removing your constructor entirely. You should be able to use the base (Sequence)Activity constructor (since you're inheriting the class, not implementing it)
Hope that helps...
I have a class like this:
namespace SharePointSocialNetworking
{
public class FeatureToEnableJob : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
// Make sure the job isn't already registered.
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
{
if (job.Name == "SPFacebookJob")
job.Delete();
}
// Install the job.
Facebook fbJob = new Facebook();
SPMinuteSchedule schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 59;
schedule.Interval = 2;
fbJob.Schedule = schedule;
fbJob.Update();
}
...
}
}
And this is my feature XML:
<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
Id="b9e40341-32ab-410a-a20f-282cf13fb54b"
ReceiverAssembly="SharePointSocialNetworking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6264b0911592ad29"
ReceiverClass="SharePointSocialNetworking.FeatureToEnableJob"
Scope="Farm"
Title="SharePoint Social Networking Job">
</Feature>
My assembly is called SharePointSocialNetworking. Am I doing anything wrong here?
I've done all the appropriate setup but when I run this command:
stsadm -o installfeature -name SharePointSocialNetworking
I get the error:
Object reference not set to an instance of an object.
your feature parent is not a site but the farm, you should not cast it to SPSite