diff --git a/src/Luban.Client/Source/Program.cs b/src/Luban.Client/Source/Program.cs index d52b04c..9d9b6e6 100644 --- a/src/Luban.Client/Source/Program.cs +++ b/src/Luban.Client/Source/Program.cs @@ -262,6 +262,10 @@ Options: else { s_logger.Error("GenJob fail. err:{err} msg:{msg}", res.ErrCode, res.ErrMsg); + if (!string.IsNullOrEmpty(res.StackTrace)) + { + s_logger.Debug("StackTrace: {}", res.StackTrace); + } } return 1; diff --git a/src/Luban.Common/Source/EErrorCode.cs b/src/Luban.Common/Source/EErrorCode.cs index d96e1f2..b90b36c 100644 --- a/src/Luban.Common/Source/EErrorCode.cs +++ b/src/Luban.Common/Source/EErrorCode.cs @@ -8,5 +8,6 @@ namespace Luban.Common READ_FILE_FAIL, JOB_ARGUMENT_ERROR, JOB_EXCEPTION, + DATA_PARSE_ERROR, } } diff --git a/src/Luban.Common/Source/Protos/GenJob.cs b/src/Luban.Common/Source/Protos/GenJob.cs index b09ff26..9deb709 100644 --- a/src/Luban.Common/Source/Protos/GenJob.cs +++ b/src/Luban.Common/Source/Protos/GenJob.cs @@ -70,6 +70,8 @@ namespace Luban.Common.Protos public List ScatteredFiles { get; set; } = new List(); + public string StackTrace { get; set; } + public override int GetTypeId() { return 0; @@ -81,6 +83,7 @@ namespace Luban.Common.Protos os.WriteString(ErrMsg); Bright.Common.SerializationUtil.Serialize(os, FileGroups); Bright.Common.SerializationUtil.Serialize(os, ScatteredFiles); + os.WriteString(StackTrace); } public override void Deserialize(ByteBuf os) { @@ -88,6 +91,7 @@ namespace Luban.Common.Protos ErrMsg = os.ReadString(); Bright.Common.SerializationUtil.Deserialize(os, FileGroups); Bright.Common.SerializationUtil.Deserialize(os, ScatteredFiles); + StackTrace = os.ReadString(); } } diff --git a/src/Luban.Job.Cfg/Source/DataCreators/DataCreateException.cs b/src/Luban.Job.Cfg/Source/DataCreators/DataCreateException.cs new file mode 100644 index 0000000..5618290 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataCreators/DataCreateException.cs @@ -0,0 +1,44 @@ +using Luban.Job.Cfg.Defs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataCreators +{ + public class DataCreateException : System.Exception + { + private List<(DefBean, DefField)> VariablePath { get; } = new(); + + public string OriginDataLocation { get; set; } + + public string DataLocationInFile { get; } + + public string OriginErrorMsg { get; } + + public string OriginStackTrace { get; } + + public DataCreateException(Exception e, string dataLocation) : base("DataCreateException", e) + { + this.OriginStackTrace = e.StackTrace; + this.OriginErrorMsg = e.Message; + this.DataLocationInFile = dataLocation; + } + + public void Push(DefBean bean, DefField f) + { + VariablePath.Add((bean, f)); + } + + public string VariableFullPathStr + { + get + { + var path = new List<(DefBean, DefField)>(VariablePath); + path.Reverse(); + return string.Join(" => ", path.Select(b => $"{{{b.Item1.FullName}}}.{b.Item2.Name}")); + } + } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs index 3b25d16..e36cee0 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs @@ -336,9 +336,16 @@ namespace Luban.Job.Cfg.DataCreators list.Add(f.CType.Apply(this, f.Remapper, new ExcelStream(stream.ReadCell(), sep, false), ass)); } } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } catch (Exception e) { - throw new InvalidExcelDataException($"读取结构:{bean.FullName} 字段:{f.Name} 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, stream.CurrentExcelPosition); + dce.Push(bean, f); + throw dce; } } return list; diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs index 0b8d61f..a92999f 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs @@ -128,9 +128,16 @@ namespace Luban.Job.Cfg.DataCreators list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow /* 肯定是 false */, f.IsNullable)); } } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } catch (Exception e) { - throw new Exception($"读取结构:{bean.FullName} 字段:{fname} 读取 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, $"列:{fname}"); + dce.Push(bean, f); + throw dce; } } else @@ -154,9 +161,16 @@ namespace Luban.Job.Cfg.DataCreators list.Add(f.CType.Apply(ExcelDataCreator.Ins, null, row.GetMultiRowStream(f.Name, sep), (DefAssembly)bean.AssemblyBase)); } } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } catch (Exception e) { - throw new Exception($"读取结构:{bean.FullName} 多行字段:{f.Name} 读取 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, ""); + dce.Push(bean, f); + throw dce; } } else @@ -166,9 +180,16 @@ namespace Luban.Job.Cfg.DataCreators { list.Add(f.CType.Apply(ExcelDataCreator.Ins, f.Remapper, stream, (DefAssembly)bean.AssemblyBase)); } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } catch (Exception e) { - throw new Exception($"读取结构:{bean.FullName} 字段:{f.Name} 位置:{stream.CurrentExcelPosition} 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, stream.CurrentExcelPosition); + dce.Push(bean, f); + throw dce; } } } diff --git a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs index fb15067..bb86620 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs @@ -130,40 +130,47 @@ namespace Luban.Job.Cfg.DataCreators } var fields = new List(); - foreach (var field in implBean.HierarchyFields) + foreach (DefField f in implBean.HierarchyFields) { - if (x.TryGetProperty(field.Name, out var ele)) + if (x.TryGetProperty(f.Name, out var ele)) { if (ele.ValueKind == JsonValueKind.Null || ele.ValueKind == JsonValueKind.Undefined) { - if (field.CType.IsNullable) + if (f.CType.IsNullable) { fields.Add(null); } else { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 不能 null or undefined "); + throw new Exception($"结构:{implBean.FullName} 字段:{f.Name} 不能 null or undefined "); } } else { try { - fields.Add(field.CType.Apply(this, ele, ass)); + fields.Add(f.CType.Apply(this, ele, ass)); + } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; } catch (Exception e) { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); + var dce = new DataCreateException(e, ""); + dce.Push(bean, f); + throw dce; } } } - else if (field.CType.IsNullable) + else if (f.CType.IsNullable) { fields.Add(null); } else { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); + throw new Exception($"结构:{implBean.FullName} 字段:{f.Name} 缺失"); } } return new DBean(bean, implBean, fields); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs index 7619559..54be78d 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs @@ -172,29 +172,36 @@ namespace Luban.Job.Cfg.DataCreators } var fields = new List(); - foreach (var field in implBean.HierarchyFields) + foreach (DefField f in implBean.HierarchyFields) { - var ele = table[field.Name]; + var ele = table[f.Name]; if (ele != null) { try { // Console.WriteLine("field:{0} type:{1} value:{2}", field.Name, ele.GetType(), ele); - fields.Add(field.CType.Apply(this, ele, ass)); + fields.Add(f.CType.Apply(this, ele, ass)); + } + catch (DataCreateException dce) + { + dce.Push(implBean, f); + throw; } catch (Exception e) { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); + var dce = new DataCreateException(e, ""); + dce.Push(bean, f); + throw dce; } } - else if (field.CType.IsNullable) + else if (f.CType.IsNullable) { fields.Add(null); } else { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); + throw new Exception($"结构:{implBean.FullName} 字段:{f.Name} 缺失"); } } return new DBean(bean, implBean, fields); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs index b59edd5..bb581e9 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs @@ -98,7 +98,8 @@ namespace Luban.Job.Cfg.DataCreators } catch (Exception e) { - throw new Exception($"位置:{stream.CurrentExcelPosition} 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, stream.CurrentExcelPosition); + throw dce; } } return list; @@ -132,7 +133,8 @@ namespace Luban.Job.Cfg.DataCreators } catch (Exception e) { - throw new Exception($"位置:{stream.CurrentExcelPosition} 出错 ==> {e.Message}", e); + var dce = new DataCreateException(e, stream.CurrentExcelPosition); + throw dce; } } return new DMap(type, map); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs index 0e1c082..9c2b6a5 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs @@ -114,26 +114,33 @@ namespace Luban.Job.Cfg.DataCreators } var fields = new List(); - foreach (var field in implBean.HierarchyFields) + foreach (DefField f in implBean.HierarchyFields) { - var feles = x.Elements(field.Name); + var feles = x.Elements(f.Name); XElement fele = feles.FirstOrDefault(); if (fele == null) { - if (field.CType.IsNullable) + if (f.CType.IsNullable) { fields.Add(null); continue; } - throw new Exception($"字段:{field.Name} 缺失"); + throw new Exception($"字段:{f.Name} 缺失"); } try { - fields.Add(field.CType.Apply(this, fele, ass)); + fields.Add(f.CType.Apply(this, fele, ass)); + } + catch (DataCreateException dce) + { + dce.Push(implBean, f); + throw; } catch (Exception e) { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); + var dce = new DataCreateException(e, ""); + dce.Push(bean, f); + throw dce; } } diff --git a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs index 8835d5b..e82d59c 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs @@ -1,3 +1,4 @@ +using Luban.Job.Cfg.DataCreators; using System; using System.IO; @@ -25,6 +26,10 @@ namespace Luban.Job.Cfg.DataSources source.Load(url, sheetName, stream, exportTestData); return source; } + catch (DataCreateException dce) + { + throw; + } catch (Exception e) { throw new Exception($"文件{url} 加载失败 ==> {e.Message}", e); diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs index 20099fa..c3a6cb7 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs @@ -1,4 +1,5 @@ using ExcelDataReader; +using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.Defs; using Luban.Job.Common.Types; @@ -66,6 +67,11 @@ namespace Luban.Job.Cfg.DataSources.Excel { datas.AddRange(sheet.ReadMulti(type, ((DefBean)type.Bean).IsMultiRow)); } + catch (DataCreateException dce) + { + dce.OriginDataLocation = sheet.RawUrl; + throw; + } catch (Exception e) { throw new Exception($"sheet:{sheet.Name} ==> {e.Message} {e.StackTrace}", e); diff --git a/src/Luban.Job.Cfg/Source/JobController.cs b/src/Luban.Job.Cfg/Source/JobController.cs index 395d273..effb4de 100644 --- a/src/Luban.Job.Cfg/Source/JobController.cs +++ b/src/Luban.Job.Cfg/Source/JobController.cs @@ -2,6 +2,7 @@ using Bright.Time; using CommandLine; using Luban.Common.Protos; using Luban.Common.Utils; +using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Generate; using Luban.Job.Cfg.RawDefs; @@ -424,6 +425,17 @@ namespace Luban.Job.Cfg res.ScatteredFiles.AddRange(genScatteredFiles); } } + catch (DataCreateException e) + { + res.ErrCode = Luban.Common.EErrorCode.DATA_PARSE_ERROR; + res.ErrMsg = $@"加载数据失败. +文件: {e.OriginDataLocation} +错误位置: {e.DataLocationInFile} +Err: {e.OriginErrorMsg} +变量: {e.VariableFullPathStr} +"; + res.StackTrace = e.OriginStackTrace; + } catch (Exception e) { res.ErrCode = Luban.Common.EErrorCode.JOB_EXCEPTION; diff --git a/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs index dae266c..8afc34c 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs @@ -1,6 +1,7 @@ using Bright.Time; using Luban.Common.Utils; using Luban.Job.Cfg.Cache; +using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; @@ -186,6 +187,14 @@ namespace Luban.Job.Cfg.Utils return record != null ? new List { record } : new List(); } } + catch (DataCreateException dce) + { + if (string.IsNullOrWhiteSpace(dce.OriginDataLocation)) + { + dce.OriginDataLocation = originFile; + } + throw; + } catch (Exception e) { throw new Exception($"配置文件:{originFile} 生成失败. ==> {e.Message}", e);