00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "libts.h"
00031
00032 #include "Error.h"
00033 #include "LogUtils.h"
00034 #include "LogField.h"
00035 #include "LogBuffer.h"
00036 #include "LogAccess.h"
00037 #include "Log.h"
00038
00039 const char *container_names[] = {
00040 "not-a-container",
00041 "cqh",
00042 "psh",
00043 "pqh",
00044 "ssh",
00045 "cssh",
00046 "ecqh",
00047 "epsh",
00048 "epqh",
00049 "essh",
00050 "ecssh",
00051 "icfg",
00052 "scfg",
00053 "record",
00054 ""
00055 };
00056
00057 const char *aggregate_names[] = {
00058 "not-an-agg-op",
00059 "COUNT",
00060 "SUM",
00061 "AVG",
00062 "FIRST",
00063 "LAST",
00064 ""
00065 };
00066
00067 LogSlice::LogSlice(char *str)
00068 {
00069 char *a, *b, *c;
00070
00071 m_enable = false;
00072 m_start = 0;
00073 m_end = INT_MAX;
00074
00075 if ((a = strchr(str, '[')) == NULL)
00076 return;
00077
00078 *a++ = '\0';
00079 if ((b = strchr(a, ':')) == NULL)
00080 return;
00081
00082 *b++ = '\0';
00083 if ((c = strchr(b, ']')) == NULL)
00084 return;
00085
00086 m_enable = true;
00087
00088
00089 while (a != b && *a == ' ') a++;
00090
00091 if (a != b)
00092 m_start = atoi(a);
00093
00094
00095 while (b != c && *b == ' ') b++;
00096
00097 if (b != c)
00098 m_end = atoi(b);
00099 }
00100
00101 int
00102 LogSlice::toStrOffset(int strlen, int *offset)
00103 {
00104 int i, j, len;
00105
00106
00107 if (m_start >= 0)
00108 i = m_start;
00109 else
00110 i = m_start + strlen;
00111
00112 if (i >= strlen)
00113 return 0;
00114
00115 if (i < 0)
00116 i = 0;
00117
00118
00119 if (m_end >= 0)
00120 j = m_end;
00121 else
00122 j = m_end + strlen;
00123
00124 if (j <= 0)
00125 return 0;
00126
00127 if (j > strlen)
00128 j = strlen;
00129
00130
00131 len = j - i;
00132
00133 if (len > 0)
00134 *offset = i;
00135
00136 return len;
00137 }
00138
00139
00140
00141
00142
00143
00144 LogField::LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, UnmarshalFunc unmarshal, SetFunc _setfunc)
00145 : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
00146 m_unmarshal_func(unmarshal), m_unmarshal_func_map(NULL), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
00147 m_time_field(false), m_alias_map(0), m_set_func(_setfunc)
00148 {
00149 ink_assert(m_name != NULL);
00150 ink_assert(m_symbol != NULL);
00151 ink_assert(m_type >= 0 && m_type < N_TYPES);
00152 ink_assert(m_marshal_func != (MarshalFunc) NULL);
00153
00154 m_time_field = (strcmp(m_symbol, "cqts") == 0
00155 || strcmp(m_symbol, "cqth") == 0
00156 || strcmp(m_symbol, "cqtq") == 0
00157 || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00158 }
00159
00160 LogField::LogField(const char *name, const char *symbol, Type type,
00161 MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, Ptr<LogFieldAliasMap> map, SetFunc _setfunc)
00162 : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
00163 m_unmarshal_func(NULL), m_unmarshal_func_map(unmarshal), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
00164 m_time_field(false), m_alias_map(map), m_set_func(_setfunc)
00165 {
00166 ink_assert(m_name != NULL);
00167 ink_assert(m_symbol != NULL);
00168 ink_assert(m_type >= 0 && m_type < N_TYPES);
00169 ink_assert(m_marshal_func != (MarshalFunc) NULL);
00170 ink_assert(m_alias_map != NULL);
00171
00172 m_time_field = (strcmp(m_symbol, "cqts") == 0
00173 || strcmp(m_symbol, "cqth") == 0
00174 || strcmp(m_symbol, "cqtq") == 0
00175 || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00176 }
00177
00178
00179 LogField::LogField(const char *field, Container container, SetFunc _setfunc)
00180 : m_name(ats_strdup(field)), m_symbol(ats_strdup(container_names[container])), m_type(LogField::STRING),
00181 m_container(container), m_marshal_func(NULL), m_unmarshal_func(NULL), m_unmarshal_func_map(NULL),
00182 m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0), m_time_field(false), m_alias_map(0), m_set_func(_setfunc)
00183 {
00184 ink_assert(m_name != NULL);
00185 ink_assert(m_symbol != NULL);
00186 ink_assert(m_type >= 0 && m_type < N_TYPES);
00187
00188 m_time_field = (strcmp(m_symbol, "cqts") == 0
00189 || strcmp(m_symbol, "cqth") == 0
00190 || strcmp(m_symbol, "cqtq") == 0
00191 || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00192
00193 switch (m_container) {
00194 case CQH:
00195 case PSH:
00196 case PQH:
00197 case SSH:
00198 case CSSH:
00199 case ECQH:
00200 case EPSH:
00201 case EPQH:
00202 case ESSH:
00203 case ECSSH:
00204 case SCFG:
00205 m_unmarshal_func = (UnmarshalFunc)&(LogAccess::unmarshal_str);
00206 break;
00207
00208 case ICFG:
00209 m_unmarshal_func = &(LogAccess::unmarshal_int_to_str);
00210 break;
00211
00212 case RECORD:
00213 m_unmarshal_func = &(LogAccess::unmarshal_record);
00214 break;
00215
00216 default:
00217 Note("Invalid container type in LogField ctor: %d", container);
00218 }
00219 }
00220
00221
00222 LogField::LogField(const LogField &rhs)
00223 : m_name(ats_strdup(rhs.m_name)), m_symbol(ats_strdup(rhs.m_symbol)), m_type(rhs.m_type), m_container(rhs.m_container),
00224 m_marshal_func(rhs.m_marshal_func), m_unmarshal_func(rhs.m_unmarshal_func), m_unmarshal_func_map(rhs.m_unmarshal_func_map),
00225 m_agg_op(rhs.m_agg_op), m_agg_cnt(0), m_agg_val(0), m_time_field(rhs.m_time_field), m_alias_map(rhs.m_alias_map), m_set_func(rhs.m_set_func)
00226 {
00227 ink_assert(m_name != NULL);
00228 ink_assert(m_symbol != NULL);
00229 ink_assert(m_type >= 0 && m_type < N_TYPES);
00230 }
00231
00232
00233
00234
00235 LogField::~LogField()
00236 {
00237 ats_free(m_name);
00238 ats_free(m_symbol);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 unsigned
00250 LogField::marshal_len(LogAccess *lad)
00251 {
00252 if (m_container == NO_CONTAINER)
00253 return (lad->*m_marshal_func) (NULL);
00254
00255 switch (m_container) {
00256 case CQH:
00257 case PSH:
00258 case PQH:
00259 case SSH:
00260 case CSSH:
00261 return lad->marshal_http_header_field(m_container, m_name, NULL);
00262
00263 case ECQH:
00264 case EPSH:
00265 case EPQH:
00266 case ESSH:
00267 case ECSSH:
00268 return lad->marshal_http_header_field_escapify(m_container, m_name, NULL);
00269
00270 case ICFG:
00271 return lad->marshal_config_int_var(m_name, NULL);
00272
00273 case SCFG:
00274 return lad->marshal_config_str_var(m_name, NULL);
00275
00276 case RECORD:
00277 return lad->marshal_record(m_name, NULL);
00278
00279 default:
00280 return 0;
00281 }
00282 }
00283
00284 void
00285 LogField::updateField(LogAccess *lad, char *buf, int len)
00286 {
00287 if (m_container == NO_CONTAINER) {
00288 return (lad->*m_set_func) (buf, len);
00289 }
00290
00291 }
00292
00293
00294
00295
00296
00297
00298 unsigned
00299 LogField::marshal(LogAccess *lad, char *buf)
00300 {
00301 if (m_container == NO_CONTAINER) {
00302 return (lad->*m_marshal_func) (buf);
00303 }
00304
00305 switch (m_container) {
00306 case CQH:
00307 case PSH:
00308 case PQH:
00309 case SSH:
00310 case CSSH:
00311 return lad->marshal_http_header_field(m_container, m_name, buf);
00312
00313 case ECQH:
00314 case EPSH:
00315 case EPQH:
00316 case ESSH:
00317 case ECSSH:
00318 return lad->marshal_http_header_field_escapify(m_container, m_name, buf);
00319
00320 case ICFG:
00321 return lad->marshal_config_int_var(m_name, buf);
00322
00323 case SCFG:
00324 return lad->marshal_config_str_var(m_name, buf);
00325
00326 case RECORD:
00327 return lad->marshal_record(m_name, buf);
00328
00329 default:
00330 return 0;
00331 }
00332 }
00333
00334
00335
00336
00337 unsigned
00338 LogField::marshal_agg(char *buf)
00339 {
00340 ink_assert(buf != NULL);
00341 int64_t avg = 0;
00342
00343 switch (m_agg_op) {
00344
00345 case eCOUNT:
00346 LogAccess::marshal_int(buf, m_agg_cnt);
00347 break;
00348
00349 case eSUM:
00350 case eFIRST:
00351 case eLAST:
00352 LogAccess::marshal_int(buf, m_agg_val);
00353 break;
00354
00355 case eAVG:
00356 if (m_agg_cnt) {
00357 avg = m_agg_val / m_agg_cnt;
00358 }
00359 LogAccess::marshal_int(buf, avg);
00360 break;
00361
00362 default:
00363 Note("Cannot marshal aggregate field %s; " "invalid aggregate operator: %d", m_symbol, m_agg_op);
00364 return 0;
00365 }
00366
00367 m_agg_val = 0;
00368 m_agg_cnt = 0;
00369
00370 return INK_MIN_ALIGN;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379 unsigned
00380 LogField::unmarshal(char **buf, char *dest, int len)
00381 {
00382 if (m_alias_map == NULL) {
00383 if (m_unmarshal_func == (UnmarshalFunc)LogAccess::unmarshal_str
00384 || m_unmarshal_func == (UnmarshalFunc)LogAccess::unmarshal_http_text) {
00385 UnmarshalFuncWithSlice func = (UnmarshalFuncWithSlice)m_unmarshal_func;
00386 return (*func) (buf, dest, len, &m_slice);
00387 }
00388 return (*m_unmarshal_func) (buf, dest, len);
00389 } else {
00390 return (*m_unmarshal_func_map) (buf, dest, len, m_alias_map);
00391 }
00392 }
00393
00394
00395
00396
00397 void
00398 LogField::display(FILE *fd)
00399 {
00400 static const char *names[LogField::N_TYPES] = {
00401 "sINT",
00402 "dINT",
00403 "STR",
00404 "IP"
00405 };
00406
00407 fprintf(fd, " %30s %10s %5s\n", m_name, m_symbol, names[m_type]);
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 bool
00417 LogField::operator==(LogField & rhs) {
00418 if (strcmp(name(), rhs.name()) || strcmp(symbol(), rhs.symbol())) {
00419 return false;
00420 } else {
00421 return true;
00422 }
00423 }
00424
00425
00426
00427 void
00428 LogField::set_aggregate_op(LogField::Aggregate agg_op)
00429 {
00430 if (agg_op > 0 && agg_op < LogField::N_AGGREGATES) {
00431 m_agg_op = agg_op;
00432 } else {
00433 Note("Invalid aggregate operator identifier: %d", agg_op);
00434 m_agg_op = NO_AGGREGATE;
00435 }
00436 }
00437
00438
00439 void
00440 LogField::update_aggregate(int64_t val)
00441 {
00442 switch (m_agg_op) {
00443
00444 case eCOUNT:
00445 case eSUM:
00446 case eAVG:
00447 m_agg_val += val;
00448 m_agg_cnt++;
00449 break;
00450
00451 case eFIRST:
00452 if (m_agg_cnt == 0) {
00453 m_agg_val = val;
00454 m_agg_cnt++;
00455 }
00456 break;
00457
00458 case eLAST:
00459 m_agg_val = val;
00460 m_agg_cnt++;
00461 break;
00462
00463 default:
00464 Note("Cannot update aggregate field; invalid operator %d", m_agg_op);
00465 return;
00466 }
00467
00468 Debug("log-agg", "Aggregate field %s updated with val %" PRId64", "
00469 "new val = %" PRId64", cnt = %" PRId64"", m_symbol, val, m_agg_val, m_agg_cnt);
00470 }
00471
00472
00473 LogField::Container LogField::valid_container_name(char *name)
00474 {
00475 for (int i = 1; i < LogField::N_CONTAINERS; i++) {
00476 if (strcmp(name, container_names[i]) == 0) {
00477 return (LogField::Container) i;
00478 }
00479 }
00480 return LogField::NO_CONTAINER;
00481 }
00482
00483
00484 LogField::Aggregate LogField::valid_aggregate_name(char *name)
00485 {
00486 for (int i = 1; i < LogField::N_AGGREGATES; i++) {
00487 if (strcmp(name, aggregate_names[i]) == 0) {
00488 return (LogField::Aggregate) i;
00489 }
00490 }
00491 return LogField::NO_AGGREGATE;
00492 }
00493
00494
00495 bool LogField::fieldlist_contains_aggregates(char *fieldlist)
00496 {
00497 bool
00498 contains_aggregates = false;
00499 for (int i = 1; i < LogField::N_AGGREGATES; i++) {
00500 if (strstr(fieldlist, aggregate_names[i]) != NULL) {
00501 contains_aggregates = true;
00502 }
00503 }
00504 return contains_aggregates;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 LogFieldList::LogFieldList()
00516 : m_marshal_len(0)
00517 { }
00518
00519 LogFieldList::~LogFieldList()
00520 {
00521 clear();
00522 }
00523
00524 void
00525 LogFieldList::clear()
00526 {
00527 LogField *f;
00528 while ((f = m_field_list.dequeue())) {
00529 delete f;
00530 }
00531 m_marshal_len = 0;
00532 }
00533
00534 void
00535 LogFieldList::add(LogField *field, bool copy)
00536 {
00537 ink_assert(field != NULL);
00538
00539 if (copy) {
00540 m_field_list.enqueue(new LogField(*field));
00541 } else {
00542 m_field_list.enqueue(field);
00543 }
00544
00545 if (field->type() == LogField::sINT) {
00546 m_marshal_len += INK_MIN_ALIGN;
00547 }
00548 }
00549
00550 LogField *
00551 LogFieldList::find_by_name(const char *name) const
00552 {
00553 for (LogField *f = first(); f; f = next(f)) {
00554 if (!strcmp(f->name(), name)) {
00555 return f;
00556 }
00557 }
00558 return NULL;
00559 }
00560
00561 LogField *
00562 LogFieldList::find_by_symbol(const char *symbol) const
00563 {
00564 LogField *field = 0;
00565
00566 if (Log::field_symbol_hash) {
00567 if (ink_hash_table_lookup(Log::field_symbol_hash, (char *) symbol, (InkHashTableValue *) & field) && field) {
00568 Debug("log-field-hash", "Field %s found", field->symbol());
00569 return field;
00570 }
00571 }
00572
00573
00574 for (field = first(); field; field = next(field)) {
00575 if (!strcmp(field->symbol(), symbol)) {
00576 return field;
00577 }
00578 }
00579
00580 return NULL;
00581 }
00582
00583 unsigned
00584 LogFieldList::marshal_len(LogAccess *lad)
00585 {
00586 int bytes = 0;
00587 for (LogField *f = first(); f; f = next(f)) {
00588 if (f->type() != LogField::sINT) {
00589 bytes += f->marshal_len(lad);
00590 }
00591 }
00592 return m_marshal_len + bytes;
00593 }
00594
00595 unsigned
00596 LogFieldList::marshal(LogAccess *lad, char *buf)
00597 {
00598 char *ptr;
00599 int bytes = 0;
00600 for (LogField *f = first(); f; f = next(f)) {
00601 ptr = &buf[bytes];
00602 bytes += f->marshal(lad, ptr);
00603 ink_assert(bytes % INK_MIN_ALIGN == 0);
00604 }
00605 return bytes;
00606 }
00607
00608 unsigned
00609 LogFieldList::marshal_agg(char *buf)
00610 {
00611 char *ptr;
00612 int bytes = 0;
00613 for (LogField *f = first(); f; f = next(f)) {
00614 ptr = &buf[bytes];
00615 bytes += f->marshal_agg(ptr);
00616 }
00617 return bytes;
00618 }
00619
00620 unsigned
00621 LogFieldList::count()
00622 {
00623 unsigned cnt = 0;
00624 for (LogField *f = first(); f; f = next(f)) {
00625 cnt++;
00626 }
00627 return cnt;
00628 }
00629
00630 void
00631 LogFieldList::display(FILE *fd)
00632 {
00633 for (LogField *f = first(); f; f = next(f)) {
00634 f->display(fd);
00635 }
00636 }