In the IP header, you have a TOTAL LENGTH header that contains "the length of the datagram, measured in octets, including internet header and data." (RFC 791).
If you want to have only the payload size of a packet, you need to do TOTAL LENGTH minus (IP Header length + (TCP|UDP) header length).
(IP header length is in the IHL header, TCP header length is in the data offset header).
With a basic tcpdump command, such as
# tcpdump -s 1500 -Svni eth0 tcp and port 80
I will display each TCP packet as follow
11:58:52.114411 IP (tos 0x0, ttl 53,id 5745, offset 0, flags [DF], proto TCP (6), length 505)
18.104.22.168.53247 > 22.214.171.124.80: Flags [P.], cksum 0x62fd (correct), seq 1193308573:1193309026, ack 2122411067, win 46, options [nop,nop,TS val 122841090 ecr 125780554], length 453
The first line contains the IP header, including the total length (length 505). The second line contains the tcp header, including the payload length (length 453), which is 505 - 52 (52 being the length of the IP + TCP headers).
If you want to automate this, you can set tcpdump to store the capture in a pcap file, and then parse the pcap with a script.
However, if you want to do it fast without degrading your performances, you should take a look at libnetfilter_queue.
That involves a bit of coding in C, but really not much. The idea is that you place a hook in netfilter to direct the trafic to you program. From there you can parse ip|tcp|udp headers and compute your information, put that in a RRD database if you want, and reinject the trafic in netfilter.